Jaka jest różnica między Instant a LocalDateTime?

255

Wiem to:

  • Instant jest raczej „techniczną” reprezentacją znaczników czasowych (nanosekund) do obliczeń.
  • LocalDateTime jest raczej reprezentacją daty / godziny, w tym stref czasowych dla ludzi.

Nadal IMO oba mogą być traktowane jako typ dla większości przypadków użycia aplikacji. Jako przykład: obecnie prowadzę zadanie wsadowe, w którym muszę obliczyć kolejny przebieg na podstawie dat i staram się znaleźć zalety / wady między tymi dwoma typami (oprócz nanosekundowej przewagi precyzji Instant i strefy czasowej) LocalDateTime).

Czy możesz wymienić niektóre przykłady aplikacji, w których należy używać tylko Instant lub LocalDateTime?

Edycja: Strzeż się błędnie odczytanych dokumentacji dla LocalDateTime dotyczących precyzji i strefy czasowej

Manuel Aldana
źródło
Instant jest bardziej elementarny, owijając standardową długość dla UTC. Dla partii typu cron nie jest to logiczny wybór.
Joop Eggen,
37
Niepoprawna definicja. LocalDateTimema nie mieć strefę czasową!
Basil Bourque,

Odpowiedzi:

828

Tabela wszystkich typów dat i godzin w Javie, zarówno nowoczesnych, jak i starszych

tl; dr

Instanti LocalDateTimesą dwoma zupełnie różnymi zwierzętami: jedno przedstawia chwilę, drugie nie.

  • Instant reprezentuje chwilę, konkretny punkt na osi czasu.
  • LocalDateTimereprezentuje 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 LocalDateTimenie 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

wprowadź opis zdjęcia tutaj

Jest Instantto 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

wprowadź opis zdjęcia tutaj

Klasa OffsetDateTimeklasy 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 ZoneOffsetklasę.

Jeśli liczba godzin-minut-sekund wynosi zero, an OffsetDateTimeoznacza moment w UTC taki sam jak an Instant.

ZoneOffset

wprowadź opis zdjęcia tutaj

ZoneOffsetKlasa oznacza grupę offsetu z-UTC , kilka godzin minutowa sekund wyprzedzając UTC lub za UTC.

A ZoneOffsetto 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

wprowadź opis zdjęcia tutaj

Strefa czasowa jest reprezentowane przez ZoneIdklasę.

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/Casablancalub Pacific/Auckland. Nigdy nie używaj 2-4-literowego skrótu, takiego jak ESTlub, ISTponieważ 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

wprowadź opis zdjęcia tutaj

Myśl ZonedDateTimekoncepcyjnie jako Instantz 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 ZonedDateTimeklasy 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

Schemat przedstawiający tylko kalendarz dla <code> LocalDate </code>.

Schemat przedstawiający tylko zegar dla <code> LocalTime </code>.

Schemat przedstawiający kalendarz plus zegar dla <code> LocalDateTime </code>.

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 Instanti ZonedDateTimeklas 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 LocalDateTimejest 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 LocalDateTimeai a ZoneId, przechowywane osobno. Później, podczas generowania harmonogramu, w locie określ moment, wzywając LocalDateTime::atZone( ZoneId )do wygenerowania ZonedDateTimeobiektu.

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 Instantz 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ć LocalDateTimew 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& LocalDateTimew szerszym kontekście.

Tabela wszystkich typów dat i godzin w Javie (zarówno współczesnych, jak i starszych), a także w standardzie SQL.

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: Instanti 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?

Tabela, z której biblioteki java.time należy korzystać, w której wersji Java lub Android

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 .

Basil Bourque
źródło
39
Świetna odpowiedź. Myślę, że pewne zamieszanie (przynajmniej moje) wynika z Localnazewnictwa. Moja intuicja dotycząca Localśrodków w odniesieniu do tego, gdzie jestem ORAZ, kiedy jestem (?!), Co prowadzi mnie do przekonania, że ​​tak naprawdę byłoby to, co ZonedDateTimejest.
mkobit
4
Tak, to jest mylące. Właśnie dlatego java.time sprytnie dodał słowo „Zoned” do DateTimenazwy klasy używanej przez jego poprzednika Joda-Time (produkującą ZonedDateTime), aby podkreślić różnicę w stosunku do klas „lokalnych”. Pomyśl o nazwie „Lokalna” jako o „skradzionej nazwie” wymagającej zastosowania w konkretnej miejscowości ”.
Basil Bourque,
2
Przedrostek ze słowem Localmoże być również sposobem na odróżnienie się od pakietu java.util, chociaż wydaje mi się, że mógł być lepszy wybór słów.
vphilipnyc
2
@simonh Wręcz przeciwnie ... Kiedy ten nowy pracownik podpisze dokumenty zatrudnienia określające ich świadczenia, w tym ubezpieczenie na życie, a następnie ten nowy czynsz wychodzi na zewnątrz na kawę tylko po to, aby zostać potrąconym i zabitym przez ciężarówkę, będzie wiele takich osób jako menedżerowie ds. zasobów ludzkich, agenci ubezpieczeniowi i prawnicy, którzy będą chcieli poznać dokładny moment, w którym nowe zatrudnienie zaczęło obowiązywać.
Basil Bourque,
2
@simonh Tak, zdarzają się przypadki, w których właściwa jest „lokalna” data i godzina. Oprócz tych wymienionych w mojej odpowiedzi, innym powszechnym przypadkiem w biznesie jest umówienie się na więcej niż kilka miesięcy w przyszłości, na tyle daleko, że politycy mogą zmienić reguły strefy czasowej, zwykle z niewielkim wyprzedzeniem. Politycy często dokonują tych zmian, takich jak zmiana dat przy włączaniu / wyłączaniu czasu letniego (DST) lub na stałe włączaniu / wyłączaniu czasu letniego.
Basil Bourque,
20

Jedną z głównych różnic jest Localczęść LocalDateTime. Jeśli mieszkasz w Niemczech i tworzysz LocalDateTimeinstancję, a ktoś inny mieszka w USA i tworzy inną instancję w tym samym momencie (pod warunkiem, że zegary są odpowiednio ustawione) - wartość tych obiektów byłaby inna. Nie dotyczy Instantto obliczania niezależnie od strefy czasowej.

LocalDateTimeprzechowuje datę i godzinę bez strefy czasowej, ale jej wartość początkowa zależy od strefy czasowej. Instantnie jest.

Ponadto LocalDateTimezapewnia metody manipulowania składnikami daty, takimi jak dni, godziny, miesiące. InstantNie.

poza nanosekundową zaletą Instant i strefą czasową LocalDateTime

Obie klasy mają tę samą precyzję. LocalDateTimenie przechowuje strefy czasowej. Przeczytaj dokładnie javadocs, ponieważ możesz popełnić duży błąd, przyjmując takie nieprawidłowe założenia: Instant i LocalDateTime .

Dariusz
źródło
przepraszam za błędne odczytanie części strefy + precyzja. Przepraszamy za powtarzanie się z powyższego postu: Rozważając zastosowanie pojedynczej strefy czasowej, w których przypadkach użycia preferowałbyś LocalDateTime lub odwrotnie?
manuel aldana
1
Biorę LocalDateTime, ilekroć potrzebuję dat i / lub godzin. Za kilka godzin, minut. Używałbym Instant do mierzenia czasu wykonania, na przykład, lub przechowywania wewnętrznego pola czegoś, co dzieje się wtedy i tam. Obliczanie kolejnych przebiegów, jak w twoim przypadku? LocalDateTime wydaje się odpowiednie, ale jest to opinia. Jak już wspomniałeś, oba mogą być używane.
Dariusz
Czy możesz opracować więcej szczegółów LocalDateTime stores date and time without timezone, but it's initial value is timezone dependent? jaka jest wartość początkowa i jak zależy od strefy czasowej? Dzięki.
Maks.
12

Mylisz się co do tego LocalDateTime: nie przechowuje żadnych informacji o strefie czasowej i ma precyzję nanosekundową. Cytując Javadoc (moje podkreślenie):

Data i godzina bez strefy czasowej w systemie kalendarzowym ISO-8601 , np. 2007-12-03T10: 15: 30.

LocalDateTime jest niezmiennym obiektem data-godzina, który reprezentuje datę-godzinę, często postrzeganą jako rok-miesiąc-dzień-godzina-minuta-sekunda. Można również uzyskać dostęp do innych pól daty i godziny, takich jak dzień roku, dzień tygodnia i tydzień roku. Czas jest reprezentowany z dokładnością do nanosekund . Na przykład wartość „2 października 2007 r. O godz. 13: 45.30.123456789” można zapisać w LocalDateTime.

Różnica między nimi polega na tym, że Instantreprezentuje przesunięcie w stosunku do Epoki (01-01-1970) i ​​jako taka reprezentuje konkretny moment na linii czasu. Dwa Instantobiekty utworzone w tym samym momencie w dwóch różnych miejscach na Ziemi będą miały dokładnie taką samą wartość.

Tunaki
źródło
Biorąc pod uwagę aplikację dla pojedynczej strefy czasowej, w jakich przypadkach użycia preferowałbyś LocalDateTime lub odwrotnie?
manuel aldana
3
@manuelaldana To bardziej kwestia gustu. Wolę LocalDateTime dla wszystkiego, co dotyczy użytkownika (urodziny ...), a Instant dla wszystkiego, co jest związane z maszyną (czas wykonania ...).
Tunaki,
2
@manuelaldana Pojedyncza aplikacja do strefy czasowej jest rzadka, jeśli nie istnieje. Możesz uciec od ignorowania stref czasowych dla małej aplikacji, którą przygotowałeś dla lokalnego klubu muzycznego w stylu barokowym. Ale gdy tylko będziesz musiał opublikować wydarzenie osobom podróżującym (i przekraczającym strefy czasowe), będą chcieli powiązać te dane ze strefą czasową, aby ich aplikacja kalendarza mogła odpowiednio dostosować. Proponuję nauczyć się prawidłowo obsługiwać strefy czasowe we wszystkich aplikacjach.
Basil Bourque,
@Tunaki Twoje użycie słowa „offset” w ostatnim akapicie jest rozpraszające. To słowo ma określone znaczenie w pracy z datą, dlatego można je tutaj wykorzystać w tym kontekście.
Basil Bourque,
0

Instant odpowiada czasowi na głównym południku (Greenwich).

Natomiast w LocalDateTimeodniesieniu do ustawień strefy czasowej systemu operacyjnego, oraz

nie może reprezentować chwili bez dodatkowych informacji, takich jak przesunięcie lub strefa czasowa.

użytkownik2418306
źródło
2
Instant opiera się na UTC, a nie GMT.
Torsten Ojaperv