В чем разница между java.util.Date и Zoneddatetime? - PullRequest
0 голосов
/ 27 февраля 2019

При использовании util.date и предоставлении даты и времени для обслуживания из браузера, а затем при сохранении в db и при возврате он дает другое время по сравнению с установкой времени zoneddate напрямую из службы.

Любая помощь будет принята..

Ответы [ 3 ]

0 голосов
/ 27 февраля 2019

Шестнадцать лет назад я написал статью для JavaWorld журнала под названием Какой у вас часовой пояс , в которой описана проблема, описанная вами при использовании класса java.util.Date.Чтобы «увидеть» значение экземпляра класса java.util.Date, вы должны преобразовать его в String.До версии java 1.8 это преобразование всегда также учитывало часовой пояс.Это одна из причин, почему в Java 1.8 был представлен новый API Date-Time.Новый код, написанный для Java версии 1.8 и выше, должен использовать новый API.Я считаю, что вам следует также рассмотреть возможность преобразования старого кода для использования нового API, если это возможно.

0 голосов
/ 27 февраля 2019

tl; dr

В чем разница между java.util.Date и Zoneddatetime?

  • Date представляет момент в UTC, тогда как ZonedDateTime представляет момент в конкретном часовом поясе.
  • Date - ужасный класс, изобилующий недостатками дизайна, который никогда не следует использовать, в то время как ZonedDateTime - это современный класс из пакета java.time , который вы найдете довольнополезно.

Java поставляется с двумя очень разными средами для обработки работы с датой и временем: ужасно неуклюжим и неудачным набором устаревших классов и современным лидирующим набором классов, найденным в java.time пакет.

Legacy ➙ modern:

  • java.util.Date заменен на java.time.Instant
    • Оба представляют моментв UTC.
  • java.util.GregorianCalendar был заменен на java.time.ZonedDateTime
    • Оба представляют момент, наблюдаемый в конкретном часовом поясе.

table of legacy and modern classes for date-time handling in Java

java.util.Date

Класс Date представляет момент в UTC.То есть дата, время суток плюс контекст UTC.

Внутренне это счет в миллисекундах с даты отсчета эпохи первого момента 1970 года в UTC, 1970-01-01T00: 00: 00Z.

Чтобы усложнить ситуацию:

  • При создании создается часовой пояс, хранящийся глубоко внутри, без геттеров и сеттеров.Таким образом, по большей части мы можем игнорировать эту зону, хотя она применима к вопросам, имеющим реализацию этого класса equals.
  • При вызове toString этот класс имеет очень сбивающее с толку поведение динамического применения текущего часового пояса JVM при генерации текста для представления значения этого объекта.Несмотря на благие намерения, эта антифункция причинила неисчислимые страдания программистам на Java, пытающимся научиться работать с датой и временем.

Смущен?Да, этот класс сбивает с толку, жалкий беспорядок плохих дизайнерских решений.Усугубляется последующим добавлением java.util.Calendar & GregorianCalendar.

Все эти проблемные классы даты и времени в комплекте с самой ранней версией Java теперь полностью заменены java.time классами.

В частности, java.util.Dateзаменяется на java.time.Instant.Оба представляют момент в UTC, считая с эпохи 1970 UTC.Но Instant имеет более высокое разрешение, наносекунды , а не миллисекунды .

Вы можете конвертировать назад и вперед между классом устаревшего Date и современнымкласс Instant путем вызова новых методов, добавленных к старому классу.Обычно вы никогда не будете использовать Date.Но при взаимодействии со старым кодом, который еще не обновлен до java.time , может потребоваться преобразование.

java.time.ZonedDateTime

Современный класс ZonedDateTime представляет собой моменткак видно на часах настенных часов, используемых людьми определенного региона (часового пояса).

Итак, Instant и ZonedDateTime похожи в том, что они оба представляют момент, конкретную точку на этой временной шкале.Разница в том, что ZonedDateTime знает о правилах часового пояса.Таким образом, ZonedDateTime знает, как учитывать аномалии, такие как переход на летнее время (DST) или другие изменения в хронометраже, требуемые политиками.

Вы можете думать об этом как:

ZonedDateTime = (Instant + ZoneId)

Мы можем легко настроить с UTCк некоторому часовому поясу, применив часовой пояс (ZoneId) к объекту Instant.

Instant instant = Instant.now() ;             // Capture the current moment as seen in UTC.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;     // Apply a time zone to see the same moment through the wall-clock time in use by the people of a particular region (a time zone). 

См. этот код , запущенный на IdeOne.com .Обратите внимание на другую дату и другое время суток, но в то же время одновременно.

instant.toString (): 2019-02-27T19: 32: 43.366Z

zdt.toString (): 2019-02-28T04: 32: 43,366 + 09: 00 [Азия / Токио]

Важная концепция: Instant и ZonedDateTime оба представляют один и тот же момент, одну и ту же одновременную точку на временной шкале.Они отличаются по времени настенных часов.Например, если кто-то в Японии звонит кому-то в Исландии (где UTC используется для своих часов все время), и они оба смотрят на часы, висящие на их соответствующих стенах, они увидят другое время суток и, возможно,даже другая дата в месячном календаре.Тот же момент, другое время настенных часов.

Что касается устаревших классов, эквивалент ZonedDateTime равен GregorianCalendar, конкретная реализация java.util.Calendar.Действительно, старый класс GregorianCalendar получил новые методы для преобразования в / из ZonedDateTime.

ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime();  // Convert from legacy to modern class.

… и…

GregorianCalendar gc = GregorianCalendar.from( zdt ) ;      // Convert from modern to legacy class.

Заключение

Таким образом, Date эквивалентно Instant, оба являются моментом в UTC.Но ZonedDateTime отличается от обоих тем, что часовой пояс скорректировал восприятие момента, применяя линзу настройки времени на часах людей региона.

Советы:

  • Никогда не используйте Date. При вручении Date немедленно преобразуйте в Instant.Затем перейдите к вашей бизнес-логике.
  • Большая часть вашей работы выполняется в UTC. Отслеживание моментов, отладка, ведение журнала, обмен значениями даты и времени и сохранение в базе данных, как правило, должны выполняться в UTC.Учитесь забывать о своем собственном приходском часовом поясе, когда работаете программистом.Держите вторые часы на вашем столе, настроенные на UTC.

База данных

Вопрос касается работы базы данных.Вот краткое резюме.Поиск переполнения стека для более подробной информации, поскольку это уже было обработано много раз.

Начиная с JDBC 4.2, мы можем напрямую обмениваться объектами java.time с базой данных.Используйте PreparedStatement::setObject и ResultSet::getObject.Больше не нужно прикасаться к ужасным java.sql.* классам, таким как java.sql.Timestamp.

Вы можете иметь возможность обменять Instant, но спецификация JDBC этого не требует.Спецификация вместо этого требует OffsetDateTime.

Извлечение.

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

И хранилище.

myPreparedStatement.setObject( … , odt ) ;

Если у вас в руке Instant, преобразуйте в OffsetDateTime с использованием константы ZoneOffset.UTC.

OffsetDateTime odt = Instant.atOffset( ZoneOffset.UTC ) ;

Чтобы просмотреть этот момент через настенное время некоторого региона, примените ZoneId.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

Чтобы сохранить ZonedDateTime в базе данных, конвертируйте вOffsetDateTime.Это лишает информацию о часовом поясе (историю прошлых, настоящих и будущих изменений, внесенных в смещение, используемое жителями этого региона по решению их политиков), оставляя дату, время дня и смещение-из UTC (количество часов, минут, секунд).

OffsetDateTime odt = zdt.toOffsetDateTime(); 

Большинство баз данных хранят момент в UTC для столбца стандартного типа SQL TIMESTAMP WITH TIMESTAMP.При отправке OffsetDateTime в базу данных ваш драйвер JDBC, скорее всего, отрегулирует смещение в OffsetDateTime до нуля часов-минут-секунд (для самого UTC).Но мне нравится делать это явно.Это облегчает отладку и демонстрирует читателю мое понимание момента, хранящегося в UTC.

OffsetDateTime odt = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC ) ; 
0 голосов
/ 27 февраля 2019

java.util.Date - это почти устаревший класс, который предоставляет обертку со значением около миллисекунды.Он не предоставляет никакой информации о часовом поясе, не имеет никаких полезных методов, и вы всегда должны избегать его использования.

ZonedDateTime - это класс из нового JDK8 API даты, который предоставляет дату и времяс часовым поясом в календарной системе ISO-8601.Вы должны проверить

Объяснение Oracle для нового формата даты

...