В чем разница между Instant и LocalDateTime?
Я знаю, что:
- Instant - это скорее "техническое" представление временной метки (наносекунды) для вычислений.
- LocalDateTime - это скорее представление даты / часов
включая часовые поясадля людей.
Тем не менее, в конце концов, IMO оба могут быть приняты за типы для большинства вариантов использования приложений. В качестве примера: в настоящее время я запускаю пакетное задание, в котором мне нужно рассчитать следующий запуск на основе дат, и я изо всех сил пытаюсь найти плюсы / минусы между этими двумя типами (кроме преимущества в наносекундной точности Instant
и части часового пояса LocalDateTime
).
Можете ли вы назвать несколько примеров приложений, в которых следует использовать только Instant
или LocalDateTime
?
Редактировать: Остерегайтесь неверно прочитанной документации для LocalDateTime
относительно точности и часового пояса.
Переведено автоматически
Ответ 1
tl; dr
Instant
и LocalDateTime
- это два совершенно разных животных: одно представляет момент, другое - нет.
Instant
представляет момент, определенную точку на временной шкале.LocalDateTime
представляет дату и время суток. Но из-за отсутствия часового пояса или смещения от UTC, этот класс не может представлять момент. Он представляет потенциальные моменты в диапазоне примерно от 26 до 27 часов, диапазон всех часовых поясов по всему миру.LocalDateTime
Значение по своей сути неоднозначно.
Неверное предположение
LocalDateTime
это скорее представление даты / часов, включая часовые пояса для людей.
Ваше утверждение неверно: у LocalDateTime
A нет часового пояса. Весь смысл этого класса в отсутствии часового пояса.
Чтобы процитировать этот класс ’ doc:
Этот класс не хранит и не представляет часовой пояс. Вместо этого это описание даты, используемое для дней рождения, в сочетании с местным временем, отображаемым на настенных часах. Он не может представлять момент времени в строке времени без дополнительной информации, такой как смещение или часовой пояс.
So Local…
означает “не зонировано, без смещения”.
Instant
An Instant
- это момент на временной шкале в UTC, отсчет в наносекунды с эпохи первого момента 1970 UTC (в принципе, подробные сведения см. в документе class doc). Поскольку большая часть вашей бизнес-логики, хранения данных и обмена данными должны выполняться в UTC, это удобный класс для частого использования.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
OffsetDateTime
Класс OffsetDateTime
class представляет момент в виде даты и времени с контекстом на некоторое количество часов-минут-секунд раньше или позже UTC. Величина смещения, количество часов-минут-секунд, представлена классом ZoneOffset
.
Если количество часов-минут-секунд равно нулю, an OffsetDateTime
представляет момент в UTC так же, как и an 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 = ( 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 ) ;
mardi 30 avril 2019 à 23 h 22 min 55 s heure de l’Inde
LocalDate
, LocalTime
, LocalDateTime
"Локальные" классы даты и времени, LocalDateTime
, LocalDate
, LocalTime
это другой вид программ. Они не привязаны к какой-либо одной местности или часовому поясу. Они не привязаны к временной шкале. Они не имеют реального значения до тех пор, пока вы не примените их к местности, чтобы найти точку на временной шкале.
Слово “Local” в этих именах классов может показаться нелогичным для непосвященных. Это слово означает любой населенный пункт или каждую местность, но не конкретную местность.
Итак, для бизнес-приложений "Локальные" типы используются не часто, поскольку они представляют лишь общее представление о возможной дате или времени, а не конкретный момент на временной шкале. Бизнес-приложения, как правило, заботятся о точном моменте поступления счета, отправки товара на транспортировку, найма сотрудника или выезда такси из гаража. Итак, разработчики бизнес-приложений чаще всего используют классы Instant
и ZonedDateTime
.
Итак, когда мы будем использовать LocalDateTime
? В трех ситуациях:
- Мы хотим применить определенную дату и время суток в нескольких местоположениях.
- Мы бронируем встречи.
- У нас предполагаемый, но не определенный часовой пояс.
Обратите внимание, что ни один из этих трех случаев не связан с одной определенной точкой на временной шкале, ни один из них не является моментом.
Одно время суток, несколько моментов
Иногда мы хотим представить определенное время суток на определенную дату, но хотим применить это к нескольким населенным пунктам в разных часовых поясах.
Например, "Рождество начинается в полночь 25 декабря 2015 года" - это LocalDateTime
. Полночь в Париже пробивает в разное время, чем в Монреале, и снова отличается в Сиэтле и в Окленде.
LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ; // 00:00:00
LocalDateTime ldt = LocalDateTime.of( ld , lt ) ; // Christmas morning anywhere.
Другой пример: "Компания Acme придерживается политики, согласно которой обеденное время начинается в 12: 30 на каждом из ее заводов по всему миру" - это LocalTime
. Чтобы получить реальное значение, вам нужно применить его к временной шкале, чтобы определить момент 12:30 на заводе в Штутгарте, или 12:30 на заводе в Рабате, или 12: 30 на заводе в Сиднее.
Бронирование встреч
Другая ситуация, которую можно использовать LocalDateTime
, - это бронирование будущих мероприятий (например, визитов к стоматологу). Эти встречи могут быть назначены достаточно далеко в будущем, и вы рискуете, что политики переопределят часовой пояс. Политики часто мало предупреждают, а то и вовсе не предупреждают. Если вы имеете в виду "15:00 следующего дня, 23 января", независимо от того, как политики могут играть с часами, то вы не можете записать момент – это привело бы к тому, что 15:00 превратились бы в 14:00 или 16:00, если бы этот регион, например, принял или отменил летнее время.
Для назначений храните a LocalDateTime
и a 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
.
Чтобы узнать больше, ознакомьтесь с Руководством по Oracle. И найдите в Stack Overflow множество примеров и пояснений. Спецификация - JSR 310.
Проект Joda-Time, который сейчас находится в режиме обслуживания, рекомендует перейти на классы java.time.
Вы можете обмениваться объектами java.time непосредственно со своей базой данных. Используйте драйвер JDBC, совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.*
классах. Поддержка Hibernate 5 и JPA 2.2 java.time.
Где получить классы java.time?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11 и более поздние версии - часть стандартного Java API с комплексной реализацией.
- Java 9 содержит некоторые незначительные функции и исправления.
- Java SE 6 и Java SE 7
- Большая часть функциональных возможностей java.time перенесена обратно на Java 6 и 7 в ThreeTen-Backport.
- Android
- Более поздние версии Android (26+) содержат реализации классов java.time.
- Для более ранних версий Android (<26) процесс, известный как десугаринг API, предоставляет подмножество функций java.time, изначально не встроенных в Android.
- Если десугаринг не предлагает того, что вам нужно, проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше) для Android. Смотрите Как использовать ThreeTenABP ....
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательным полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и больше.
Ответ 2
Одним из основных отличий является "локальная" часть LocalDateTime
. Если вы живете в Германии и создаете LocalDateTime
экземпляр, а кто-то другой живет в США и создает другой экземпляр в тот же самый момент (при условии, что часы установлены правильно) - значение этих объектов на самом деле будет другим. Это не относится к Instant
, который вычисляется независимо от часового пояса.
LocalDateTime
дата и время хранятся без часового пояса, но их начальное значение зависит от часового пояса. Instant
's - нет.
Более того, LocalDateTime
предоставляет методы для манипулирования компонентами даты, такими как дни, часы и месяцы. An Instant
этого не делает.
помимо преимущества в наносекундной точности
Instant
и части часового пояса вLocalDateTime
Оба класса имеют одинаковую точность. LocalDateTime
не сохраняет часовой пояс. Внимательно читайте Javadocs, потому что вы можете совершить большую ошибку с такими неверными предположениями: Instant
и LocalDateTime
.
Ответ 3
Вы ошибаетесь насчет LocalDateTime
: он не хранит никакой информации о часовом поясе и имеет наносекундную точность. Цитирую Javadoc (выделено мной):
Дата-время без часового пояса в календарной системе ISO-8601, например 2007-12-03T10:15:30.
LocalDateTime
это неизменяемый объект date-time, который представляет дату-время, часто рассматриваемый как год-месяц-день-час-минута-секунда. Также доступны другие поля даты и времени, такие как day-of-year, day-of-week и week-of-year. Время представлено с точностью до наносекунды. Например, значение "2 октября 2007 года в 13:45.30.123456789" может храниться вLocalDateTime
.
Разница между ними заключается в том, что Instant
представляет смещение от эпохи (01-01-1970) и, как таковой, представляет конкретный момент времени на временной шкале. Два Instant
объекта, созданные в один и тот же момент в двух разных местах на Земле, будут иметь точно такое же значение.
Ответ 4
LocalDateTime не содержит информации о часовом поясе: одно LocalDateTime может представлять разные моменты времени для разных машин по всему миру. Поэтому вам не следует пытаться использовать его с неявным часовым поясом (системным по умолчанию). Вы должны использовать это для того, что оно представляет, например, "Новый год 1 января, в 0: 00": это означает разное время во всех точках земного шара, но в данном случае это необходимо.
Instant - это момент времени в часовом поясе по Гринвичу. Используйте его в дополнение к часовому поясу пользователя, например, чтобы показать ему начало встречи в его часовом поясе.
Если эти два класса не представляют то, что вы хотели сохранить / обменять, то, возможно, ZonedDateTime или другой класс справятся с этой задачей лучше.
Вот простая синтетическая схема для получения общей картины классов в пакете java.time и их связи со стандартом ISO-8601, используемым для надежного и легкого обмена датами и временем между Java и другими языками или фреймворками:
Схема подробно объясняется здесь: http://slaout.linux62.org/java-date-time /