Java Date и MySQL timestamp часовой пояс - PullRequest
0 голосов
/ 23 января 2019

Я редактирую фрагмент кода, который в основном делает:

timestamp = new Date();

И затем сохраняю эту переменную timestamp в TIMESTAMP столбце таблицы MySQL.
Однако, пока через отладку ясм. объект Date, отображаемый в правильном часовом поясе, GMT + 1 , когда он сохраняется в базе данных, это часовой пояс GMT , поэтому час назад.

Использование функции CURRENT_TIMESTAMP возвращает дату по Гринвичу + 1.
Строка подключения jdbc:mysql://..../db-name, без каких-либо параметров.

РЕДАКТИРОВАТЬ : Найден этот фрагмент кода

preparedStatement.setTimestamp(2, new Timestamp(timestamp.getTime()));

Что происходит?

1 Ответ

0 голосов
/ 23 января 2019

tl; dr

myPreparedStatement
.setObject(  
    … ,                                   // Specify which placeholder `?` in your SQL statement. 
    OffsetDateTime.now( ZoneOffset.UTC )  // Capture the current moment as seen in the wall-clock time of UTC (an offset-from-UTC of zero).
) ;

Избегайте устаревших классов даты и времени

Вы используете ужасные классы даты и времени, которые были вытеснены несколько лет назад java.time классы.

Никогда не используйте Date или Timestamp.

UTC

Захват текущего момента в UTC.Большинство баз данных хранят момент в UTC.И, как правило, вы должны выполнять большую часть своей бизнес-логики, отладки, регистрации, хранения и обмена данными в UTC.

OffsetDateTime

Представьте момент со смещением от UTC, используяметко названный OffsetDateTime класс.

Нам нужен сам UTC или нулевое смещение.Мы можем использовать константу для этого, ZoneOffset.UTC.

OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ) ;

JDBC 4.2

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

Чтобы сохранить этот момент в столбце типа данных, аналогичного стандарту SQL TIMESTAMP WITH TIME ZONE:

myPreparedStatement.setObject( … , odt ) ;

Получение:

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

ZonedDateTime

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

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

Никогда не полагайтесь на часовой пояс по умолчанию

Обратите внимание, что в приведенном выше коде мы всегда указывали желаемое / ожидаемое смещение или зону.

Если вы не укажете, смещение или зона применяются неявно неявно.Лучше явно указать свои намерения, так как текущие настройки по умолчанию для вашей JVM, базы данных и хост-операционной системы - все это не в ваших руках программиста.Это означает, что код, полагающийся на значение по умолчанию, будет изменяться в поведении во время выполнения.

Java 6 & 7

Однако я все еще вынужден иметь дело с Java 6

Тот же человек, Стивен Колебурн, который возглавляет JSR 310и реализация java.time , а также знаменитый проект Joda-Time также ведут другой проект, ThreeTen-Backport .Большая часть функциональности java.time перенесена обратно в Java 6 и 7 в этой библиотеке с почти идентичным API.

Так что выполняйте всю свою работу в классах бэк-порта.Затем, в последний момент, конвертируйте в / из java.sql.Timestamp через класс DateTimeUtils.

В этих методах преобразования в основном используются Instant объекты.Instant - это момент в UTC, всегда в UTC.Вы можете отрегулировать значение от OffsetDateTime до UTC, извлекая Instant.Класс Instant является базовым классом строительных блоков в java.time , причем OffsetDateDate обладает большей гибкостью, такой как альтернативные шаблоны форматирования при генерации строки.Но и Instant, и OffsetDateTime представляют момент, точку на временной шкале.

Instant instant = odt.toInstant() ;  
java.sql.Timestamp ts = org.threeten.bp.DateTimeUtils.toSqlTimestamp( instant ) ;

В другом направлении, извлекая Timestamp из вашей базы данных, а затем немедленно преобразуя в Instant,

java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
Instant instant = org.threeten.bp.DateTimeUtils.toInstant( ts ) ;

О 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 .

...