В чем разница между Instant и LocalDateTime?
Я знаю, что:
Тем не менее, в конце концов, IMO оба могут быть приняты за типы для большинства вариантов использования приложений. В качестве примера: в настоящее время я запускаю пакетное задание, в котором мне нужно рассчитать следующий запуск на основе дат, и я изо всех сил пытаюсь найти плюсы / минусы между этими двумя типами (кроме преимущества в наносекундной точности Instant
и части часового пояса LocalDateTime
).
Можете ли вы назвать несколько примеров приложений, в которых следует использовать только Instant
или LocalDateTime
?
Редактировать: Остерегайтесь неверно прочитанной документации для LocalDateTime
относительно точности и часового пояса.
Переведено автоматически
Ответ 1
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 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?
Проект 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 /