
ТЛ; др
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

Класс OffsetDateTimeclass представляет момент в виде даты и времени с контекстом, состоящим из некоторого количества часов, минут и секунд перед или после 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, и более .