LocalDateTime
Внимательно прочитайте документацию.
Этот класс не хранит и не представляет часовой пояс. Вместо этого, это описание даты, используемой для дней рождений, в сочетании с местным временем, показанным на настенных часах. Он не может представлять момент на временной шкале без дополнительной информации, такой как смещение или часовой пояс.
Класс LocalDateTime
в Java нельзя использовать для представления момента. Он представляет потенциальные моменты в диапазоне около 26-27 часов, диапазоне часовых поясов по всему земному шару.
Этот класс содержит дату и время суток, но намеренно не имеет понятия о часовом поясе или смещении от UTC. Поэтому, если вы храните, например, полдень 23 января этого года, мы не знаем, имели ли вы в виду полдень в Токио, Калькутте, Париже или Монреале ... все разные моменты, с разницей в часах, происходили раньше на востоке, а затем в Запад.
Итак, вы используете неправильный класс. На мгновение используйте Instant
, OffsetDateTime
или ZonedDateTime
.
TIMESTAMP
Внимательно прочитайте документацию.
Тип TIMESTAMP
в MySQL 8 похож на тип SQL-стандарта TIMESTAMP WITH TIME ZONE
. Этот тип представляет момент, конкретную точку на временной шкале.
Документация объясняет , что момент, переданный в базу данных, настроен на UTC для хранения.
MySQL преобразует TIMESTAMP
значений из текущего часового пояса в UTC для хранения и обратно из UTC в текущий часовой пояс для извлечения.
Это объясняет вашу проблему. Вы неявно полагались на то, что текущий часовой пояс по умолчанию назначается объекту неправильного типа в Java, в котором отсутствует какой-либо часовой пояс. Никогда не пишите код, который зависит от текущего часового пояса по умолчанию (или локали) вашего сервера, так как он находится вне вашего контроля программиста. Вместо этого всегда указывайте явно желаемый / ожидаемый часовой пояс. Или лучше, просто по возможности работайте в UTC.
Для получения наилучших результатов придерживайтесь UTC при обмене значениями с базой данных.
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
индексирование.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Чтобы просмотреть этот момент через часы настенного времени, используемые людьми определенного региона, примените ZoneId
, чтобы получить ZonedDateTime
.
ZoneId z = ZoneId.of( "Australia/Sydney" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
![Table of date-time types in Java (both modern and legacy) and in standard SQL.](https://i.stack.imgur.com/yiiHr.png)