Выбор даты UTC в Oracle и преобразование в UTC в Java - PullRequest
0 голосов
/ 13 сентября 2018

Если я позвоню в моем приложении:

System.currentTimeMillis()

результат будет, скажем, 1536842771599, , то есть : GMT: четверг, 13 сентября, 2018 12: 46: 11,599 вечера ИЛИ в мой местный : четверг, сентябрь 13, 2018 3: 46: 11.599 вечера по Гринвичу + 03:00 по летнему времени

Если я сделаю следующее, выберите базу данных Oracle, установленную локально:

select CAST(sys_extract_utc(SYSTIMESTAMP) AS DATE) from dual;

Я получаю через следующий код JdbcTemplate:

jdbc.queryForObject(sqlCommand, new Object[0], Timestamp.class);

следующий результат: enter image description here

Что, на мой взгляд, уже неверно, поскольку метка времени обычно представляет собой локализованное время. Далее, если я позвоню:

myResult.getTime()

чтобы получить длинное значение, это конвертирует мое время, которое было около 12.46 PM, в значение 1536831971599, которое на самом деле: GMT: четверг, 13 сентября, 2018 9: 46: 11.599 AM.

Очевидно, что это не очень хорошо, потому что это на 2 * GMT + 03: 00 (6 часов) отстает от моего фактического местного времени, а GMT + 03: 00 (3 часа) отстает от времени UTC Базы данных.

Что я делаю не так? Мой единственный вывод до сих пор состоит в том, чтобы не делать sys_extract_utc для базы данных и позволить базе данных возвращать мне местное время, которое будет преобразовано в время UTC, когда я вызову getTime для экземпляра Timestamp.

Есть какое-нибудь объяснение этому?

P.S. Основываясь на ответе о том, что java.sql.Timestamp - это UTC, я прилагаю скриншот того, что мне показывает отладчик, и что это неверно, потому что он считает результат, который является UTC, GMT + 03: 00. Итак, он показывает мое время как 8,26 + 03:00. Мое местное время 11.26. Если я вызову getTime для этого экземпляра Timestamp, я получу длинное значение, которое, если я введу в https://www.epochconverter.com/, получу пятницу, 14 сентября, 2018 8:26:06 AM GMT + 03: 00 DST или пятницу , 14 сентября 2018 года, 5:26:06, что ровно на 3 часа меньше, чем у меня на UTC!

P.S.2 Я использую Spring JDBC 4.2.5-RELEASE. Не может использовать Instant с ним, он генерирует исключение, которое не может конвертировать Timestamp в Instant, потому что он ожидает что-то, что происходит от Number. Я не могу изменить этот JDBC, даже версию, сейчас, к сожалению.

enter image description here

1 Ответ

0 голосов
/ 13 сентября 2018

tl; dr

Вы неправильно понимаете класс java.sql.Timestamp.

  • java.sql.Timestamp всегда представляет момент в UTC.
  • java.time.Instant лет назад заменен Timestamp.

Используйте только Instant, никогда Timestamp.

Instant

Ужасный класс java.sql.Timestamp теперь устарел из java.time классов, в частности Instant.

Instant.now()  // Capture the current moment in UTC. 

JDBC 4.2

Начиная с JDBC 4.2 мы можем напрямую обмениваться java.time объектами с базой данных.Больше не нужно использовать классы ужасных Date, Calendar или java.sql.

Получить.

Instant instant = myResultSet.getObject( … , Instant.class ) ;

Вставить.

myPreparedStatement.setObject( … , instant ) ;

Метка времени обычно представляет собой локализованное время.

Неправильно.java.sql.Timestamp представляет момент в UTC, всегда UTC, по определению.Аналогично, Instant также представляет момент в UTC.Оба класса представляют собой счет с первого момента 1970 года в UTC.


О 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 SE 11 и более поздние версии - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большая часть функций java.time перенесена на Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии реализации пакета Android для java.time классы.
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .

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

...