В чем разница между Instant и LocalDateTime?

256

Я знаю это:

  • Instant - это скорее «техническое» представление меток времени (наносекунды) для вычислений.
  • LocalDateTime - это скорее представление даты / часов, включая часовые пояса для людей.

Тем не менее, в конце концов, IMO можно использовать как тип для большинства случаев применения. Как пример: в настоящее время я выполняю пакетное задание, в котором мне нужно рассчитать следующий прогон на основе дат, и я изо всех сил пытаюсь найти плюсы / минусы между этими двумя типами (кроме преимущества точности в наносекундах в Instant и части часового пояса). LocalDateTime).

Можете ли вы назвать примеры приложений, в которых следует использовать только Instant или LocalDateTime?

Изменить: Остерегайтесь неверно прочитанных документов для LocalDateTime относительно точности и часового пояса

Мануэль Алдана
источник
Instant более элементарен, оборачивая стандартную длинную для UTC. Для cron-подобной партии не очень логичный выбор.
Joop Eggen
37
Неверное определение. LocalDateTimeэто не имеет часовой пояс!
Базилик Бурк

Ответы:

834

Таблица всех типов даты и времени в Java, как современных, так и устаревших

ТЛ; др

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

Диаграмма, показывающая только календарь для <code> LocalDate </ code>.

Диаграмма, показывающая только часы для <code> LocalTime </ code>.

Диаграмма, показывающая календарь и часы для <code> LocalDateTime </ code>.

«Местный» классы дат и времени, 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 (как современных, так и устаревших), а также стандарта SQL.

Обратите внимание на странный выбор, сделанный командой 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?

  • Java SE 8 , Java SE 9 , Java SE 10 и более поздние версии
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии Android связывают реализации классов java.time.
    • Для более ранних версий Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). Смотрите Как использовать ThreeTenABP… .

Таблица какой библиотеки java.time использовать с какой версией Java или Android

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь , такие как Interval, YearWeek, YearQuarter, и более .

Базилик Бурк
источник
40
Отличный ответ. Я думаю, что некоторая путаница (по крайней мере, моя) происходит от Localименования. Моя интуиция Localозначает средства относительно того, где я нахожусь и когда я нахожусь (?!), И это заставляет меня поверить, что это действительно то, что ZonedDateTimeесть.
mkobit
4
Да, это сбивает с толку. Вот почему java.time ловко добавил слово «Zoned» к имени DateTimeкласса, используемому его предшественником Joda-Time (производящий ZonedDateTime), чтобы подчеркнуть отличие от «локальных» классов. Думайте о названии «Локальный» как о сокращении «нужно применять к определенной местности».
Василий Бурк
2
Префикс перед словом, Localвозможно, также был способом отличить пакет java.util, хотя я чувствую, что мог бы быть лучший выбор слова.
vphilipnyc
2
@simonh Напротив… Когда этот новый сотрудник подпишет свои документы о найме, определяющие их льготы, в том числе страхование жизни, а затем этот новый наем выйдет на улицу, чтобы выпить кофе только для того, чтобы его сбил грузовик, таких людей будет много. как менеджеры по персоналу, страховые агенты и адвокаты, которые захотят узнать точный момент, когда эта новая занятость вступила в силу.
Василий Бурк
2
@simonh Да, есть случаи, когда подходит местное время. Помимо упомянутых в моем ответе, еще один распространенный случай в бизнесе - это назначения на более чем пару месяцев в будущем, достаточно далеко, чтобы политики могли изменить правила часового пояса, обычно с небольшим предупреждением. Политики часто вносят эти изменения, такие как изменение дат при включении / выключении летнего времени (DST) или постоянное включение / выключение DST.
Василий Бурк
20

Одним из основных отличий является Localчасть LocalDateTime. Если вы живете в Германии и создаете LocalDateTimeэкземпляр, а кто-то еще живет в США и в тот же момент создает другой экземпляр (при условии, что часы установлены правильно) - значение этих объектов на самом деле будет другим. Это не относится к тому Instant, что рассчитывается независимо от часового пояса.

LocalDateTimeсохраняет дату и время без часового пояса, но его начальное значение зависит от часового пояса. Instantэто не так.

Кроме того, LocalDateTimeпредоставляет методы для манипулирования такими компонентами даты, как дни, часы, месяцы. Ан Instantнет.

кроме преимущества наносекундной точности Instant и часового пояса LocalDateTime

Оба класса имеют одинаковую точность. LocalDateTimeне хранит часовой пояс. Внимательно читайте javadocs, потому что вы можете совершить большую ошибку с такими неверными предположениями: Instant и LocalDateTime .

Дариуш
источник
извините за неправильное прочтение части по зоне + точность. Извините за повторение вышеприведенного поста: Рассматривая одно приложение для часовых поясов, в каких случаях вы бы предпочли LocalDateTime или наоборот?
Мануэль Алдана
1
Я бы взял LocalDateTime всякий раз, когда мне нужны даты и / или время. В часах, минутах или около того. Например, я бы использовал Instant для измерения времени выполнения или для хранения внутреннего поля sth, происходящего тогда и там. Подсчет следующих прогонов, как в твоем случае? LocalDateTime кажется подходящим, но это мнение. Как вы заявили, оба могут быть использованы.
Дариуш
Можете ли вы уточнить подробнее LocalDateTime stores date and time without timezone, but it's initial value is timezone dependent? что такое начальное значение и как оно зависит от часового пояса? Спасибо.
Макс
12

Вы ошибаетесь LocalDateTime: он не хранит информацию о часовом поясе и обладает точностью до наносекунды. Цитирую Javadoc (выделение мое):

Дата-время без часового пояса в календарной системе ISO-8601 , например 2007-12-03T10: 15: 30.

LocalDateTime - это неизменный объект даты-времени, который представляет дату-время, часто рассматриваемый как год-месяц-день-час-минута-секунда. Другие поля даты и времени, такие как день года, день недели и неделя года, также могут быть доступны. Время представляется с точностью до наносекунды . Например, значение «2 октября 2007 года в 13: 45.30.123456789» может быть сохранено в LocalDateTime.

Разница между ними заключается в том, что она Instantпредставляет собой смещение от эпохи (01-01-1970) и, как таковая, представляет определенный момент на временной шкале. Два Instantобъекта, созданные в один и тот же момент в двух разных местах Земли, будут иметь абсолютно одинаковое значение.

Tunaki
источник
Рассматривая одно приложение для часовых поясов, в каких случаях вы бы предпочли LocalDateTime или наоборот?
Мануэль Алдана
3
@manuelaldana Это больше вопрос вкуса. Я бы предпочел LocalDateTime для всего, что связано с пользователем (день рождения ...) и Instant для всего, что связано с машиной (время выполнения ...).
Тунаки
2
@manuelaldana Одно приложение для часовых поясов встречается редко, если вообще не существует. Вам может не понравиться игнорирование часовых поясов для небольшого приложения, которое вы взяли для своего местного музыкального клуба в стиле барокко. Но как только вам нужно будет опубликовать событие для людей, которые путешествуют (и пересекают часовые пояса), они захотят, чтобы эти данные были привязаны к часовому поясу, чтобы их приложение календаря могло корректироваться по мере необходимости. Я предлагаю вам научиться правильно работать с часовыми поясами во всех ваших приложениях.
Базилик Бурк
@Tunaki Использование слова «смещение» в последнем абзаце отвлекает. Это слово имеет определенный смысл в работе с датой и временем, поэтому его использование здесь в этом контексте может оказаться бесполезным.
Базилик Бурк
0

Instant соответствует времени на простом меридиане (Гринвич).

Принимая во внимание, что LocalDateTimeотносительно настроек часового пояса ОС, и

не может представлять момент без дополнительной информации, такой как смещение или часовой пояс.

user2418306
источник
2
Момент основан на UTC, а не по Гринвичу.
Торстен