Яка різниця між Instant і LocalDateTime?


255

Я це знаю:

  • Миттєвий швидше - це "технічне" представлення часових позначок (наносекунд) для обчислень.
  • LocalDateTime - це швидше представлення дати / годинника, включаючи часові пояси для людей.

Але врешті-решт ІМО обидва можна вважати типом для більшості випадків використання додатків. Наприклад, зараз я виконую пакетну роботу, де мені потрібно обчислити наступний запуск на основі дат, і я намагаюся знайти плюси / мінуси між цими двома типами (крім переваги наносекундної точності в режимі миттєвого та часової зони з LocalDateTime).

Чи можете ви назвати деякі приклади програм, де слід використовувати лише Instant або LocalDateTime?

Редагувати: Остерігайтеся непрочитаних документацій для LocalDateTime щодо точності та часового поясу


Миттєвий - більш елементарний, тривалий час триває UTC. Для партії, подібної до хронів, вибір не такий логічний
Joop Eggen

37
Неправильне визначення. LocalDateTimeце НЕ має часовий пояс!
Василь Бурк

Відповіді:


828

Таблиця всіх типів дат та часу на Java, як сучасних, так і застарілих

тл; д-р

Instantі LocalDateTimeце дві абсолютно різні тварини: одна уособлює момент, інша - ні.

  • Instant являє собою момент, конкретну точку на часовій шкалі.
  • LocalDateTimeявляє собою дату і час дня. Але відсутній часовий пояс або зміщений з-за UTC, цей клас не може представляти момент . Він представляє потенційні моменти в межах від 26 до 27 годин, діапазон усіх часових поясів по всьому світу.

Неправильна презумпція

LocalDateTime це швидше представлення дати / годинника, включаючи часові пояси для людини.

Ваше твердження не так: не має ні часового поясу . Немає часового поясу - це вся точка цього класу.LocalDateTime

Щоб процитувати цей клас 'doc:

Цей клас не зберігає і не представляє часовий пояс. Натомість це опис дати, яка використовується для днів народження, у поєднанні з місцевим часом, як це видно на настінному годиннику. Він не може представляти мить на часовій лінії без додаткової інформації, такої як зміщення чи часовий пояс.

Таким чином, Local…означає "не зоновано, не зрушено".

Instant

введіть тут опис зображення

InstantЦе момент на шкалі часу в форматі UTC , відлік наносекунд після епохи перших кроків 1970 UTC ( в основному, см класу документа для деталей суворих буднів). Оскільки більша частина вашої ділової логіки, зберігання даних та обміну даними має бути в UTC, це зручний клас, який часто використовується.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

OffsetDateTime

введіть тут опис зображення

Клас OffsetDateTimeкласу представляє момент як дату і час з контекстом на деяку кількість годин-хвилин-секунд перед або за UTC. Величина зміщення, кількість годин-хвилин-секунд, представлена ZoneOffsetкласом.

Якщо кількість годин-хвилин-секунд дорівнює нулю, то OffsetDateTimeпозначає момент в UTC такий же, як і Instant.

ZoneOffset

введіть тут опис зображення

ZoneOffsetКлас являє собою зсув від-UTC- , кількість годин-хвилин-секунд попереду UTC або позаду UTC.

A ZoneOffset- це лише кількість годин-хвилин-секунд, нічого більше. Зона набагато більше, має назву та історію змін, які можна змінити. Тому використання зони завжди бажано використовувати просто зміщення.

ZoneId

введіть тут опис зображення

Часовий пояс представлена ZoneIdкласом.

Наприклад, новий день світиться раніше в Парижі, ніж в Монреалі . Тому нам потрібно рухати руками годинника, щоб краще відобразити полудень (коли Сонце знаходиться прямо над головою) для певного регіону. Чим далі на схід / захід від лінії UTC на заході Європи / Африки, тим більше зміщення.

Часовий пояс - це сукупність правил поводження з коригуваннями та аномаліями, що застосовуються місцевою громадою чи регіоном. Найпоширеніша аномалія - ​​надто популярний лунатик, відомий як літній час (DST) .

У часовому поясі є історія минулих правил, теперішніх правил та правил, підтверджених на найближче майбутнє.

Ці правила змінюються частіше, ніж ви могли очікувати. Не забудьте постійно оновлювати правила бібліотеки дат, як правило, копію бази даних 'tz' . Оновити оновлення у Java 8 простіше, ніж будь-коли зараз, за ​​допомогою Oracle випустити інструмент оновлення часової зони .

Вкажіть правильний час ім'я зони в форматі Continent/Region, наприклад America/Montreal, Africa/Casablancaабо Pacific/Auckland. Ніколи не використовуйте абревіатуру 2-4 літер, наприклад, ESTабо ISTяк вони не є справжніми часовими поясами, не стандартизовані і навіть не унікальні (!).

Часова зона = Зсув + Правила коригування

ZoneId z = ZoneId.of( Africa/Tunis ) ; 

ZonedDateTime

введіть тут опис зображення

Подумайте про ZonedDateTimeконцептуально як Instantпро присвоєне ZoneId.

ZonedDateTime = (Миттєвий + ZoneId)

Для того, щоб зафіксувати поточний момент, як це бачимо у настінний годинник, який використовують люди певного регіону (часовий пояс):

ZonedDateTime zdt = ZonedDateTime.now( z ) ;  // Pass a `ZoneId` object such as `ZoneId.of( "Europe/Paris" )`. 

Майже всі ваші бекенд, база даних, ділова логіка, постійність даних, обмін даними повинні бути в UTC. Але для презентації користувачам потрібно налаштувати на часовий пояс, який очікує користувач. Це призначення ZonedDateTimeкласу та класів форматорів, які використовуються для створення рядкових представлень цих значень дати та часу.

ZonedDateTime zdt = instant.atZone( z ) ;
String output = zdt.toString() ;                 // Standard ISO 8601 format.

Ви можете генерувати текст у локалізованому форматі, використовуючи DateTimeFormatter.

DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ; 
String outputFormatted = zdt.format( f ) ;

mardi 30 квітня 2019 р. до 23 год. 22 хв. 55 s heure de l'Inde

LocalDate, LocalTime,LocalDateTime

Діаграма, що показує лише календар для <code> LocalDate </code>.

Діаграма, що показує лише годинник для <code> LocalTime </code>.

Діаграма, що показує календар плюс годинник для <code> LocalDateTime </code>.

«Місцевий» класи дат і часу, LocalDateTime, LocalDate, LocalTime, є різного роду звірка. Вони не прив'язані до жодної місцевості чи часового поясу. Вони не прив’язані до часової шкали. Вони не мають реального значення, поки ви не застосуєте їх до місцевості, щоб знайти точку на часовій шкалі.

Слово "Місцевий" у назвах цих класів може бути протиінтуїтивним для непосвячених. Слово означає будь-який населений пункт або кожен населений пункт, але не конкретний населений пункт.

Так, для бізнес-додатків типи "Місцеві" часто не використовуються, оскільки вони представляють лише загальну думку про можливу дату чи час, а не конкретний момент на шкалі часу. Бізнес-програми, як правило, дбають про точний момент надходження рахунку-фактури, доставку товару для транспорту, найманого працівника або таксі покинули гараж. Тож розробники бізнес-додатків використовують Instantта ZonedDateTimeзаняття найчастіше.

То коли б ми використовували LocalDateTime? У трьох ситуаціях: коли ми хочемо застосувати певну дату та час дня в декількох місцях, де ми бронюємо зустрічі або де у нас передбачений ще невизначений часовий пояс. Зауважте, що жоден із цих трьох випадків не є окремим певним моментом на часовій шкалі, жоден із них не є моментом.

Один час дня, кілька моментів

Іноді ми хочемо відобразити певний час доби в певну дату, але хочемо застосувати це до кількох місцевостей у часових поясах.

Наприклад, "Різдво починається опівночі 25 грудня 2015 року" - це LocalDateTime. Опівночі нападає в різні моменти в Парижі, ніж в Монреалі, і знову в Сіетлі та в Окленді .

LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ;   // 00:00:00
LocalTime ldt = LocalDateTime.of( ld , lt ) ;  // Xmas morning anywhere. 

Інший приклад: "Компанія Acme має політику, що обід розпочинається о 12:30 на кожному з заводів по всьому світу" - це LocalTime. Щоб мати справжнє значення, вам потрібно застосувати його до часової шкали, щоб відобразити момент 12:30 на фабриці в Штутгарті або 12:30 на фабриці в Рабаті або 12:30 на фабриці в Сіднеї .

Зустрічі на бронювання

Інша ситуація, яку слід використовувати LocalDateTimeдля бронювання майбутніх подій (наприклад: Зустрічі стоматолога). Ці призначення можуть виявитись досить далеко в майбутньому, якщо ви ризикуєте політикам переосмислити часовий пояс. Політики часто дають мало попередження або взагалі не попереджають. Якщо ви маєте на увазі "3:00 наступного дня 23 січня", незалежно від того, як політики можуть грати з годинником, то ви не можете зафіксувати хвилини - це побачило б, що 15:00 перетвориться на 14:00 чи 16:00, якщо цей регіон прийняв або відмовив від літнього часу, наприклад.

Для зустрічей зберігайте окремі LocalDateTimeта "а" ZoneId, що зберігаються окремо. Пізніше, створюючи графік, на ходу визначають момент, викликаючи LocalDateTime::atZone( ZoneId )створення ZonedDateTimeоб'єкта.

ZonedDateTime zdt = ldt.atZone( z ) ;  // Given a date, a time-of-day, and a time zone, determine a moment, a point on the timeline.

Якщо потрібно, ви можете налаштувати на UTC. Витяг Instantз ZonedDateTime.

Instant instant = zdt.toInstant() ;  // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.

Невідома зона

Деякі люди можуть використовуватись LocalDateTimeу ситуації, коли часовий пояс або зміщення невідомі.

Я вважаю цей випадок недоречним і нерозумним. Якщо зона чи зміщення призначені, але невизначені, у вас є погані дані. Це було б як зберігання ціни товару, не знаючи призначеної валюти. Не гарна ідея.

Усі типи дати та часу

Для повноти тут наведена таблиця всіх можливих типів дати та часу, як сучасних, так і застарілих на Java, а також тих, що визначені стандартом SQL. Це може допомогти розмістити Instant& LocalDateTimeкласи в більш широкому контексті.

Таблиця всіх типів дати в Java (як сучасна, так і застаріла), а також стандарт SQL.

Помітьте незвичайні варіанти, зроблені командою Java при розробці JDBC 4.2. Вони вирішили підтримувати всі часи java.time … за винятком двох найпоширеніших класів: Instant& ZonedDateTime.

Але не хвилюватися. Ми можемо легко конвертувати назад і назад.

Перетворення Instant.

// Storing
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject(  , odt ) ;

// Retrieving
OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;

Перетворення 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 ) ; 

Про java.time

Java.time каркас вбудований в Java 8 і пізніших версій. Ці класи витісняти неприємні старі застарілі класи дати і часу , такі як java.util.Date, Calendar, і SimpleDateFormat.

Проект Joda-Time , який зараз знаходиться в режимі обслуговування , радить перейти до класів java.time .

Щоб дізнатися більше, дивіться навчальний посібник Oracle . І шукайте переповнення стека за багатьма прикладами та поясненнями. Специфікація - JSR 310 .

Ви можете обмінюватися об'єктами java.time безпосередньо зі своєю базою даних. Використовуйте драйвер JDBC, сумісний з JDBC 4.2 або пізнішої версії. Немає потреби в струнах, немає потреби в java.sql.*заняттях.

Де отримати класи java.time?

  • Java SE 8 , Java SE 9 , Java SE 10 та новіших версій
    • Вбудований.
    • Частина стандартного Java API з пакетною реалізацією.
    • Java 9 додає деякі незначні функції та виправлення.
  • Java SE 6 та Java SE 7
    • Значна частина функцій java.time підтримується на Java 6 і 7 у ThreeTen-Backport .
  • Android
    • Пізніші версії реалізації пакетів Android для класів java.time.
    • Для більш ранньої Android (<26), то ThreeTenABP проект адаптує ThreeTen-Backport (згаданий вище). Див. Як користуватися ThreeTenABP… .

Таблиця, яку бібліотеку java.time використовувати в якій версії Java або Android

Проект ThreeTen-Extra розширює java.time додатковими класами. Цей проект є передумовою для можливих майбутніх доповнень до java.time. Ви можете знайти деякі корисні класи тут , такі як Interval, YearWeek, YearQuarter, і більш .


39
Чудова відповідь. Я думаю, що деяка плутанина (принаймні моя) походить від Localназивання. Моя інтуїція щодо Localзасобів стосовно того, де я є І коли я є (?!), Що приводить мене до думки, що це насправді було б, що ZonedDateTimeє.
mkobit

4
Так, це заплутано. Ось чому java.time спритно додав слово "Zoned" до назви DateTimeкласу, використовуваного його попередником Joda-Time (виробництво ZonedDateTime), щоб підкреслити відмінність від класів "Local". Подумайте про назву "Місцевий" як скорочення для "потребувати застосування до певної місцевості".
Василь Бурк

2
Префіксація слова Localможе бути також способом відрізнятись від пакета java.util, хоча я якось вважаю, що міг бути кращий вибір слова.
vphilipnyc

2
@simonh Навпаки ... Коли цей новий працівник підписує свої документи про наймання, визначаючи їх переваги, включаючи страхування життя, а потім, що нові кроки наймають на вулицю, щоб випити кави лише для того, щоб потрапити та вбити вантажівкою, таких людей буде багато як менеджери з персоналу, страхові агенти та адвокати, які хочуть дізнатися точний момент, коли ця нова зайнятість набула чинності.
Василь Бурк

2
@simonh Так, є випадки, коли "місцевий" час дати є відповідним. Окрім тих, що згадуються у моєму відповіді, ще одна поширена справа в бізнесі - це призначення на посади більше ніж на пару місяців у майбутньому, досить далеко, щоб політики могли змінити правила часового поясу, як правило, з невеликим попередженням. Політики часто вносять ці зміни, такі як зміна дат під час ввімкнення / вимкнення літнього часу (DST) або постійного перебування на / вимкненому доступі.
Василь Бурк

20

Одна головна відмінність - це Localчастина LocalDateTime. Якщо ви живете в Німеччині і створюєте LocalDateTimeекземпляр, а хтось інший живе в США і створює інший екземпляр у той самий момент (за умови правильного встановлення годинника) - значення цих об’єктів насправді було б іншим. Це не стосується Instant, що розраховується незалежно від часового поясу.

LocalDateTimeзберігає дату та час без часового поясу, але початкове значення залежить від часового поясу. InstantРосія ні.

Більше того, LocalDateTimeпередбачені методи маніпулювання компонентами дати, такими як дні, години, місяці. А Instantні.

крім переваги точності наносекунди Instant та часової зони у LocalDateTime

Обидва класи мають однакову точність. LocalDateTimeне зберігає часовий пояс. Ретельно читайте javadocs, тому що ви можете зробити велику помилку з такими недійсними припущеннями: Instant і LocalDateTime .


вибачте за неправильне прочитання частини про зону + точність. Вибачте за повторення з вищезгаданого повідомлення: Розглядаючи єдину програму часового поясу, у яких випадках використання ви б віддали перевагу LocalDateTime чи навпаки?
мануель альдана

1
Я б приймав LocalDateTime, коли мені потрібні дати та / або час. За години, хвилини тощо. Я б використав "Миттєве" для вимірювання часу виконання, наприклад, або для зберігання внутрішнього поля того, що відбувається тоді і там. Обчислення наступних циклів, як у вашому випадку? LocalDateTime здається доречним, але це думка. Як ви заявили, обидва можна використовувати.
Даріуш

Чи можете ви детальніше розповісти LocalDateTime stores date and time without timezone, but it's initial value is timezone dependent? що таке початкове значення і як це залежить від часового поясу? Дякую.
Макс

12

Ви помиляєтесь LocalDateTime: вона не зберігає інформацію про часовий пояс і має наносекундну точність. Цитуючи Javadoc (моє наголос):

Дата-час без часового поясу в системі календарів ISO-8601 , наприклад 2007-12-03T10: 15: 30.

LocalDateTime - це незмінний об'єкт дати-часу, який представляє дату-час, який часто розглядається як рік-місяць-день-година-година-хвилина. Також можна отримати доступ до інших полів дати та часу, таких як день року, день тижня та тиждень року. Час представлено до наносекундної точності . Наприклад, значення "2 жовтня 2007 о 13: 45.30.123456789" може зберігатися у LocalDateTime.

Різниця між ними полягає в тому, що Instantявляє собою зміщення від Епохи (01-01-1970) і, як таке, являє собою певний момент на часовій лінії. Два Instantоб’єкти, створені в один і той же момент у двох різних місцях Землі, матимуть абсолютно однакове значення.


Розглядаючи єдину програму часового поясу, у яких випадках використання ви б віддавали перевагу LocalDateTime чи навпаки?
мануель альдана

3
@manuelaldana Це більше питання смаку. Я віддаю перевагу LocalDateTime для будь-якого, що стосується користувачів (день народження ...), і Миттєвий для будь-якого, що стосується машини (час виконання ...).
Тунакі

2
@manuelaldana Додаток для єдиного часового поясу рідко, якщо не існує. Ви можете відійти від ігнорування часових поясів для невеликого додатка, який ви підключили до місцевого музичного клубу в стилі бароко. Але як тільки вам потрібно опублікувати подію людям, які подорожують (і перетинають часові пояси), вони захочуть, щоб ці дані були прив’язані до часового поясу, щоб їх програма в календарі могла коригуватись за потребою. Я пропоную вам навчитися правильно працювати з часовими поясами у всіх своїх програмах.
Василь Бурк

@Tunaki Використання слова "компенсувати" в останньому абзаці відволікає. Це слово має певне значення у роботі з датою та часом, тому його використання тут у цьому контексті може бути не корисним.
Василь Бурк

0

Instant відповідає часу на меридіані (Грінвіч).

Враховуючи LocalDateTimeналаштування часового поясу ОС, і

не може представляти мить без додаткової інформації, такої як зміщення чи часовий пояс.


2
Миттєвий пошук базується на UTC, а не GMT.
Торстен Ожаперв
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.