тл; д-р
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
«Місцевий» класи дат і часу, 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 при розробці 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?
Проект ThreeTen-Extra розширює java.time додатковими класами. Цей проект є передумовою для можливих майбутніх доповнень до java.time. Ви можете знайти деякі корисні класи тут , такі як Interval
, YearWeek
, YearQuarter
, і більш .