Проблема сохранения текущей даты с временем UTC на сервере sql - PullRequest
0 голосов
/ 25 сентября 2019

Я хочу сохранить дату с UTC часовым поясом в sql server 2014. Я использовал ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("UTC")), чтобы получить текущую дату и время и сохранить ее в БД, используя объект сеанса Hibernate.Во время отладки я вижу, что в программе Java хорошо работает дата, например 2019-09-25T13:22:29.573Z[UTC], но после сохранения в столбце базы данных она выглядит примерно так 2019-09-25 18:53:23.3630000.Это автоматически конвертирует часть времени в соответствии с системным временем.Кто-нибудь может подсказать, в чем проблема?Я использовал datetime2 тип данных при создании этого столбца в базе данных.

1 Ответ

0 голосов
/ 25 сентября 2019

Неправильный тип

Вы используете неверный тип данных для своего столбца.

Тип datetime2 не может представлять момент. Этот тип хранит только дату и время дня, но не имеет контекста часового пояса или смещения от UTC,Поэтому, если вы храните «полдень 23 января 2020 года», мы не можем знать, имели ли вы в виду полдень в Токио, Япония, полдень в Тунисе, Тунис, или полдень в Толедо, штат Огайо, США, три разных момента с интервалом в несколько часов.Этот неправильный тип похож на стандартный тип SQL TIMESTAMP WITHOUT TIME ZONE.Эквивалентный класс в Java - LocalDateTime.

Если у вас уже есть данные, вам необходимо реорганизовать вашу базу данных .По сути, добавьте новый столбец правильного типа, скопируйте данные для каждой строки, конвертируя по ходу работы.Конечно, это работает, только если вы знаете предполагаемый часовой пояс, который отсутствовал в каждом сохраненном значении.

Правильный тип

Хотя я не использую Microsoft SQL Server, в соответствии с документом вы должны использовать столбец типа datetimeoffset для записи момента .Этот тип корректирует любое переданное значение в UTC для запросов и сортировки, а также записывает смещение.Этот тип похож на стандартный тип SQL TIMESTAMP WITH TIME ZONE.

Обычно лучше всего хранить свои моменты в формате UTC, смещение нуля часов, минут и секунд.

Класс Instant представляет момент в UTC.

Instant instant = Instant.now() ;

Если у вас есть ZonedDateTime, вы можете извлечь Instant.

Instant instant = zdt.toInstant() ;

Мы хотели бы сохранить это Instant непосредственно в базе данных.К сожалению, для JDBC 4.2 soec не требуется поддержка ни одного из двух наиболее часто используемых java.time классов: Instant и ZonedDateTime.Спецификация требует поддержки OffsetDateTime.Итак, мы конвертируем.

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

Добавить в базу данных.

myPreparedStatement.setObject( … , odt ) ; 

Retrieve.

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

Извлеките Instant, чтобы указать в своем коде, что вы хотите использовать UTC.

Instant instant = odt.toInstant() ;

Посмотрите этот момент через настенные часы, используемые людьми определенного региона (часового пояса).

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

Table of date-time types in Java (both legacy and modern) and in standard SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...