ТЛ; др
Instant
и LocalDateTime
два совершенно разных животных: одно представляет момент, другое нет.
Instant
представляет момент, конкретную точку на временной шкале.
LocalDateTime
представляет дату и время суток. Но без часового пояса или смещения от UTC этот класс не может представлять момент . Он представляет потенциальные моменты в диапазоне от 26 до 27 часов, диапазон всех часовых поясов по всему земному шару.
Неверная презумпция
LocalDateTime
скорее представление даты / часов, включая часовые пояса для людей.
Ваше утверждение неверно: A LocalDateTime
не имеет часового пояса . Отсутствие часового пояса - весь смысл этого класса.
Процитируем документ этого класса:
Этот класс не хранит и не представляет часовой пояс. Вместо этого это описание даты, используемой для дней рождений, в сочетании с местным временем, показанным на настенных часах. Он не может представлять момент на временной шкале без дополнительной информации, такой как смещение или часовой пояс.
Так Local…
значит «не зонировано, нет смещения».
Instant
Это Instant
момент на временной шкале в UTC , подсчет наносекунд со времени первого момента 1970 UTC (в основном, см. Подробности в документе doc). Поскольку большая часть вашей бизнес-логики, хранилища данных и обмена данными должна быть в формате UTC, этот класс удобно использовать часто.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
OffsetDateTime
Класс OffsetDateTime
class представляет момент в виде даты и времени с контекстом, состоящим из некоторого количества часов, минут и секунд перед или после UTC. Количество смещения, количество часов-минут-секунд, представлено ZoneOffset
классом.
Если число часов-минут-секунд равно нулю, OffsetDateTime
то момент времени в UTC представляет собой то же самое, что и момент времени Instant
.
ZoneOffset
ZoneOffset
Класс представляет собой смещение от-UTC- , количество часов-минут-секунд впереди UTC или позади UTC.
А ZoneOffset
это просто количество часов-минут-секунд, не более того. Зона намного больше, имеет имя и историю изменений для смещения. Поэтому использование зоны всегда предпочтительнее, чем простое смещение.
ZoneId
Временная зона представлена ZoneId
классом.
Например, в Париже новый день наступает раньше, чем в Монреале . Поэтому нам нужно передвинуть стрелки часов, чтобы лучше отразить полдень (когда Солнце находится прямо над головой) для данного региона. Чем дальше на восток / запад от линии UTC в Западной Европе / Африке, тем больше смещение.
Часовой пояс - это набор правил для обработки корректировок и аномалий, практикуемых местным сообществом или регионом. Самая распространенная аномалия - это слишком популярное безумие, известное как летнее время .
Часовой пояс имеет историю прошлых правил, настоящих правил и правил, подтвержденных на ближайшее будущее.
Эти правила меняются чаще, чем вы могли ожидать. Обязательно обновляйте правила библиотеки даты и времени, обычно копии базы данных '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 = (Instant + 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 ) ;
Марди 30 Аврил 2019 г. 23 ч. 22 мин. 55 с.
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 часа дня следующего января 23-го» независимо от того, как политики могут играть с часами, то вы не можете записать момент - это будет означать, что 3 часа дня превратятся в 14 или 16 часов, если в этом регионе будет принят или отменен переход на летнее время, например.
Для встреч храните А 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 Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .
Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, соответствующий JDBC 4.2 или более поздней версии . Нет необходимости в строках, нет необходимости в java.sql.*
классах.
Где взять классы java.time?
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь , такие как Interval
, YearWeek
, YearQuarter
, и более .