tl; dr
Instant
i LocalDateTime
są dwoma zupełnie różnymi zwierzętami: jedno przedstawia chwilę, drugie nie.
Instant
reprezentuje chwilę, konkretny punkt na osi czasu.
LocalDateTime
reprezentuje datę i porę dnia. Jednak bez strefy czasowej lub przesunięcia względem UTC klasa ta nie może reprezentować chwili . Przedstawia potencjalne momenty w zakresie od około 26 do 27 godzin, zakres wszystkich stref czasowych na całym świecie.
Błędne domniemanie
LocalDateTime
jest raczej reprezentacją daty / godziny, w tym stref czasowych dla ludzi.
Twoje oświadczenie jest nieprawidłowe: A LocalDateTime
nie ma strefy czasowej . Brak strefy czasowej to cały punkt tej klasy.
Aby zacytować ten dokument klasy:
Ta klasa nie przechowuje ani nie reprezentuje strefy czasowej. Zamiast tego jest to opis daty stosowanej na urodziny, w połączeniu z czasem lokalnym widocznym na zegarku ściennym. Nie może reprezentować chwili na linii czasu bez dodatkowych informacji, takich jak przesunięcie lub strefa czasowa.
Local…
Oznacza to więc „bez stref, bez przesunięcia”.
Instant
Jest Instant
to moment na osi czasu w UTC , liczba nanosekund od epoki pierwszego momentu 1970 UTC (w zasadzie, patrz dokument klasy, aby uzyskać szczegóły nitty-ziarnistości). Ponieważ większość logiki biznesowej, przechowywania danych i wymiany danych powinna odbywać się w UTC, jest to przydatna klasa, z której można często korzystać.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
OffsetDateTime
Klasa OffsetDateTime
klasy reprezentuje moment jako datę i godzinę w kontekście pewnej liczby godzin-minut-sekund przed lub za UTC. Wielkość przesunięcia, liczba godzin-minut-sekund, jest reprezentowana przez ZoneOffset
klasę.
Jeśli liczba godzin-minut-sekund wynosi zero, an OffsetDateTime
oznacza moment w UTC taki sam jak an Instant
.
ZoneOffset
ZoneOffset
Klasa oznacza grupę offsetu z-UTC , kilka godzin minutowa sekund wyprzedzając UTC lub za UTC.
A ZoneOffset
to tylko liczba godzin-minut-sekund, nic więcej. Strefa to znacznie więcej, z nazwą i historią zmian do przesunięcia. Dlatego korzystanie ze strefy jest zawsze lepsze niż zwykłe przesunięcie.
ZoneId
Strefa czasowa jest reprezentowane przez ZoneId
klasę.
Na przykład nowy dzień zaczyna się wcześniej w Paryżu niż na przykład w Montrealu . Musimy więc przesunąć wskazówki zegara, aby lepiej odzwierciedlić południe (gdy Słońce jest bezpośrednio nad głową) dla danego regionu. Im dalej na wschód / zachód od linii UTC w zachodniej Europie / Afryce, tym większe przesunięcie.
Strefa czasowa to zestaw zasad postępowania z korektami i anomaliami praktykowanymi przez lokalną społeczność lub region. Najczęstszą anomalią jest bardzo popularna szaleństwo zwane czasem letnim (DST) .
Strefa czasowa ma historię przeszłych reguł, obecnych reguł i reguł potwierdzonych w najbliższej przyszłości.
Reguły te zmieniają się częściej, niż można się spodziewać. Pamiętaj o aktualizowaniu reguł biblioteki daty i czasu, zwykle kopii bazy danych „tz” . Utrzymywanie aktualności jest teraz łatwiejsze niż kiedykolwiek w Javie 8 dzięki Oracle udostępniającemu narzędzie aktualizacji stref czasowych .
Określ prawidłową nazwę strefy czasowej w formacie Continent/Region
, takie jak America/Montreal
, Africa/Casablanca
lub Pacific/Auckland
. Nigdy nie używaj 2-4-literowego skrótu, takiego jak EST
lub, IST
ponieważ nie są to prawdziwe strefy czasowe, nie są znormalizowane, a nawet unikalne (!).
Strefa czasowa = przesunięcie + zasady regulacji
ZoneId z = ZoneId.of( “Africa/Tunis” ) ;
ZonedDateTime
Myśl ZonedDateTime
koncepcyjnie jako Instant
z przypisanym ZoneId
.
ZonedDateTime = (Instant + ZoneId)
Aby uchwycić bieżący moment widziany w zegarze ściennym używanym przez mieszkańców danego regionu (strefy czasowej):
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Pass a `ZoneId` object such as `ZoneId.of( "Europe/Paris" )`.
Prawie wszystkie zaplecze, baza danych, logika biznesowa, trwałość danych, wymiana danych powinny być w UTC. Ale w celu prezentacji użytkownikom musisz dostosować się do strefy czasowej oczekiwanej przez użytkownika. Taki jest cel ZonedDateTime
klasy i klas formaterów używanych do generowania reprezentacji ciągu tych wartości daty i godziny.
ZonedDateTime zdt = instant.atZone( z ) ;
String output = zdt.toString() ; // Standard ISO 8601 format.
Możesz generować tekst w zlokalizowanym formacie za pomocą DateTimeFormatter
.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ;
String outputFormatted = zdt.format( f ) ;
Wtorek 30 Kwiecień 2019 23 h 22 min 55 s heure de l'Inde
LocalDate
, LocalTime
,LocalDateTime
Te „lokalne” Klasy czas data, LocalDateTime
, LocalDate
, LocalTime
, są różnego rodzaju stwora. Nie są powiązane z żadną lokalizacją ani strefą czasową. Nie są powiązane z osią czasu. Nie mają żadnego rzeczywistego znaczenia, dopóki nie zastosujesz ich do lokalizacji, aby znaleźć punkt na osi czasu.
Słowo „lokalny” w tych nazwach klas może być sprzeczne z intuicją dla niewtajemniczonych. Słowo oznacza dowolną lokalizację lub każdą lokalizację, ale nie określoną lokalizację.
Dlatego w przypadku aplikacji biznesowych typy „lokalne” nie są często używane, ponieważ reprezentują one jedynie ogólne pojęcie możliwej daty lub godziny, a nie określonego momentu na osi czasu. Aplikacje biznesowe zwykle dbają o to, kiedy dokładnie dotrze faktura, produkt wysłany do transportu, pracownik został zatrudniony lub taksówka opuściła garaż. Dzięki czemu programiści aplikacji biznesowych użytku Instant
i ZonedDateTime
klas najczęściej.
Kiedy więc użyjemy LocalDateTime
? W trzech sytuacjach: gdy chcemy zastosować określoną datę i porę dnia w wielu lokalizacjach, gdzie rezerwujemy terminy spotkań lub w której mamy zamierzoną, jeszcze nieokreśloną strefę czasową. Zauważ, że żaden z tych trzech przypadków nie jest pojedynczym określonym punktem na osi czasu, żaden z nich nie jest momentem.
Jedna pora dnia, wiele chwil
Czasami chcemy przedstawić określoną porę dnia w określonym dniu, ale chcemy zastosować to w wielu lokalizacjach w różnych strefach czasowych.
Na przykład „Boże Narodzenie zaczyna się o północy 25 grudnia 2015 r.” LocalDateTime
. Północ wybija w różnych momentach w Paryżu niż w Montrealu, a także w Seattle i Auckland .
LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ; // 00:00:00
LocalTime ldt = LocalDateTime.of( ld , lt ) ; // Xmas morning anywhere.
Kolejny przykład: „Firma Acme ma politykę, zgodnie z którą pora obiadowa zaczyna się o godzinie 12:30 w każdej z fabryk na całym świecie” LocalTime
. Aby mieć prawdziwe znaczenie, należy zastosować go do osi czasu, aby określić moment 12:30 w fabryce w Stuttgarcie lub 12:30 w fabryce Rabat lub 12:30 w fabryce w Sydney .
Rezerwacja terminów
Inną sytuacją do wykorzystania LocalDateTime
jest rezerwacja przyszłych wydarzeń (np. Wizyty u dentysty). Spotkania te mogą być na tyle daleko w przyszłości, że ryzykujesz, że politycy redefiniują strefę czasową. Politycy często dają niewiele ostrzeżeń, a nawet nie ostrzegają wcale. Jeśli masz na myśli „15 po południu w dniu 23 stycznia”, niezależnie od tego, jak politycy mogą grać z zegarem, to nie możesz nagrać chwili - to oznaczałoby, że godzina piętnasta zamieni się w 14 lub 16 po południu, jeśli region ten przyjmie lub skróci czas letni, na przykład.
W przypadku spotkań przechowuj LocalDateTime
ai a ZoneId
, przechowywane osobno. Później, podczas generowania harmonogramu, w locie określ moment, wzywając LocalDateTime::atZone( ZoneId )
do wygenerowania ZonedDateTime
obiektu.
ZonedDateTime zdt = ldt.atZone( z ) ; // Given a date, a time-of-day, and a time zone, determine a moment, a point on the timeline.
W razie potrzeby możesz dostosować się do UTC. Wyodrębnij Instant
z ZonedDateTime
.
Instant instant = zdt.toInstant() ; // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.
Nieznana strefa
Niektóre osoby mogą używać LocalDateTime
w sytuacji, gdy strefa czasowa lub przesunięcie są nieznane.
Uważam tę sprawę za nieodpowiednią i nierozsądną. Jeśli strefa lub przesunięcie jest zamierzone, ale nie jest określone, masz złe dane. To byłoby jak przechowywanie ceny produktu bez znajomości zamierzonej waluty. To nie jest dobry pomysł.
Wszystkie typy daty i godziny
Dla kompletności, oto tabela wszystkich możliwych typów daty i godziny, zarówno nowoczesnych, jak i starszych w Javie, a także tych zdefiniowanych przez standard SQL. Może to pomóc w umieszczeniu klas Instant
& LocalDateTime
w szerszym kontekście.
Zwróć uwagę na dziwne wybory dokonane przez zespół Java przy projektowaniu JDBC 4.2. Zdecydowali się obsługiwać wszystkie czasy java.time … z wyjątkiem dwóch najczęściej używanych klas: Instant
i ZonedDateTime
.
Ale nie martw się. Możemy łatwo konwertować tam iz powrotem.
Konwersja Instant
.
// Storing
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
// Retrieving
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;
Konwersja ZonedDateTime
.
// Storing
OffsetDateTime odt = zdt.toOffsetDateTime() ;
myPreparedStatement.setObject( … , odt ) ;
// Retrieving
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZone( z ) ;
O java.time
Środowisko java.time jest wbudowane w Javę 8 i nowsze wersje . Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date
, Calendar
, i SimpleDateFormat
.
Projekt Joda-Time , teraz w trybie konserwacji , zaleca migrację do klas java.time .
Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj stos przepełnienia dla wielu przykładów i wyjaśnień. Specyfikacja to JSR 310 .
Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie potrzeba ciągów, nie ma potrzeby java.sql.*
klas.
Gdzie można uzyskać klasy java.time?
Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak Interval
, YearWeek
, YearQuarter
, i więcej .