Как я могу настроить JPA / Hibernate для хранения даты / времени в базе данных как часового пояса UTC (GMT)? Рассмотрим этот аннотированный объект JPA:
public class Event {
@Id
public int id;
@Temporal(TemporalType.TIMESTAMP)
public java.util.Date date;
}
Если дата - 3 февраля 2008 г., 9:30 утра по тихоокеанскому стандартному времени (PST), то я хочу, чтобы в базе данных сохранялось время в формате UTC 3 февраля 2008 г., 17:30. Точно так же, когда дата извлекается из базы данных, я хочу, чтобы она интерпретировалась как UTC. Таким образом, в этом случае 17:30 - это 17:30 по всемирному координированному времени. Когда он отображается, он будет отформатирован как 9:30 по тихоокеанскому стандартному времени.
Ответы:
В Hibernate 5.2 теперь вы можете установить часовой пояс UTC, используя следующее свойство конфигурации:
Подробнее читайте в этой статье .
источник
useTimezone=true
в строке подключения. Тогдаhibernate.jdbc.time_zone
будет работать только свойство настройкиuseLegacyDatetimeCode
falseНасколько мне известно, вам нужно поместить все свое приложение Java в часовой пояс UTC (чтобы Hibernate сохранял даты в UTC), и вам нужно будет преобразовать в любой часовой пояс, который требуется при отображении материала (по крайней мере, мы это делаем сюда).
При запуске делаем:
И установите желаемый часовой пояс в DateFormat:
источник
Hibernate игнорирует данные о часовых поясах в Dates (потому что их нет), но на самом деле это уровень JDBC, который вызывает проблемы.
ResultSet.getTimestamp
иPreparedStatement.setTimestamp
оба говорят в своих документах, что они по умолчанию преобразуют даты в / из текущего часового пояса JVM при чтении и записи из / в базу данных.Я придумал решение этой проблемы в Hibernate 3.5, создав подкласс,
org.hibernate.type.TimestampType
который заставляет эти методы JDBC использовать UTC вместо местного часового пояса:То же самое следует сделать, чтобы исправить TimeType и DateType, если вы используете эти типы. Обратной стороной является то, что вам придется вручную указать, что эти типы должны использоваться вместо значений по умолчанию в каждом поле даты в ваших POJO (а также нарушает чистую совместимость с JPA), если кто-то не знает более общего метода переопределения.
ОБНОВЛЕНИЕ: Hibernate 3.6 изменил API типов. В версии 3.6 я написал класс UtcTimestampTypeDescriptor для реализации этого.
Теперь, когда приложение запускается, если вы установите для TimestampTypeDescriptor.INSTANCE экземпляр UtcTimestampTypeDescriptor, все временные метки будут сохраняться и обрабатываться как находящиеся в формате UTC без необходимости изменять аннотации в POJO. [Я еще не тестировал это]
источник
UtcTimestampType
?UtcTimestampType
совместима?Date
илиTimestamp
зависит от драйвера JDBC.С Spring Boot JPA используйте приведенный ниже код в файле application.properties, и, очевидно, вы можете изменить часовой пояс по своему выбору.
Затем в вашем файле класса Entity
источник
Добавление ответа, полностью основанного на divestoclimb, с подсказкой от Шона Стоуна. Просто хотел подробно рассказать об этом, так как это обычная проблема, и решение ее немного сбивает с толку.
Здесь используется Hibernate 4.1.4.Final, хотя я подозреваю, что после 3.6 все будет работать.
Сначала создайте UtcTimestampTypeDescriptor divestoclimb
Затем создайте UtcTimestampType, который использует UtcTimestampTypeDescriptor вместо TimestampTypeDescriptor в качестве SqlTypeDescriptor в вызове суперконструктора, но в противном случае делегирует все TimestampType:
Наконец, когда вы инициализируете конфигурацию Hibernate, зарегистрируйте UtcTimestampType как переопределение типа:
Теперь временные метки не должны быть связаны с часовым поясом JVM на пути к базе данных и из нее. HTH.
источник
Можно подумать, что эту распространенную проблему решит Hibernate. Но это не так! Есть несколько "приемов", чтобы исправить это.
Я использую для хранения Date как Long в базе данных. Поэтому я всегда работаю с миллисекундами после 1/1/70. Затем у меня есть геттеры и сеттеры в моем классе, которые возвращают / принимают только даты. Так что API остается прежним. Обратной стороной является то, что у меня длинные позиции в базе данных. Итак, с SQL я могу делать только сравнения <,>, = - не причудливые операторы даты.
Другой подход - пользовательский тип сопоставления, как описано здесь: http://www.hibernate.org/100.html
Я думаю, что правильный способ справиться с этим - использовать календарь вместо даты. С помощью календаря вы можете установить часовой пояс перед сохранением.
ПРИМЕЧАНИЕ. Глупый stackoverflow не позволяет мне комментировать, поэтому вот ответ давиду а.
Если вы создадите этот объект в Чикаго:
Hibernate сохраняет его как «31.12.1969 18:00:00». В датах не должно быть часового пояса, поэтому я не уверен, зачем нужно было вносить изменения.
источник
Calendar
проблему чтения, я думаю, что Hibernate или JPA должны предоставить какой-то способ указать для каждого сопоставления часовой пояс, в который Hibernate должен переводить дату, которую он читает и записывает вTIMESTAMP
столбец.Timestamp
поскольку мы не можем обязательно доверять драйверу JDBC для хранения дат как мы ожидали.Здесь действуют несколько часовых поясов:
Все они могут быть разными. Hibernate / JPA имеет серьезный недостаток дизайна, заключающийся в том, что пользователь не может легко обеспечить сохранение информации о часовом поясе на сервере базы данных (что позволяет восстановить правильное время и дату в JVM).
Без возможности (легко) сохранять часовой пояс с помощью JPA / Hibernate информация теряется, и как только информация теряется, ее создание становится дорогостоящим (если это вообще возможно).
Я бы сказал, что лучше всегда хранить информацию о часовом поясе (должна быть по умолчанию), и тогда у пользователей должна быть дополнительная возможность оптимизировать часовой пояс (хотя это действительно влияет только на отображение, все еще есть неявный часовой пояс в любой дате).
Извините, этот пост не предоставляет обходной путь (на который ответили в другом месте), но это рационализация того, почему всегда важно хранить информацию о часовом поясе. К сожалению, кажется, что многие компьютерные ученые и практики программирования возражают против необходимости часовых поясов просто потому, что они не осознают перспективу «потери информации» и то, как это очень затрудняет такие вещи, как интернационализация, что очень важно в наши дни, когда веб-сайты доступны для клиенты и люди в вашей организации, когда они перемещаются по миру.
источник
Взгляните на мой проект на Sourceforge, в котором есть типы пользователей для стандартных типов даты и времени SQL, а также для JSR 310 и Joda Time. Все типы пытаются решить проблему компенсации. См. Http://sourceforge.net/projects/usertype/
РЕДАКТИРОВАТЬ: В ответ на вопрос Дерека Махара, прикрепленный к этому комментарию:
«Крис, ваши типы пользователей работают с Hibernate 3 или новее? - Дерек Махар, 7 ноября 2010 г., 12:30»
Да, эти типы поддерживают версии Hibernate 3.x, включая Hibernate 3.6.
источник
Дата не находится в каком-либо часовом поясе (это офис в миллисекундах от определенного момента времени, одинакового для всех), но базовые (R) БД обычно хранят временные метки в политическом формате (год, месяц, день, час, минута, секунда,. ..) с учетом часового пояса.
Если серьезно, Hibernate ДОЛЖЕН быть разрешен в рамках некоторой формы сопоставления, что дата БД находится в таком-то часовом поясе, чтобы при загрузке или сохранении она не предполагала своего собственного ...
источник
Я столкнулся с той же проблемой, когда хотел сохранить даты в БД как UTC и избежать использования
varchar
явныхString <-> java.util.Date
преобразований или установки всего моего приложения Java в часовом поясе UTC (потому что это может привести к другим неожиданным проблемам, если JVM используется во многих приложениях).Итак, есть проект с открытым исходным кодом
DbAssist
, который позволяет легко исправить чтение / запись как дату UTC из базы данных. Поскольку вы используете аннотации JPA для сопоставления полей в сущности, все, что вам нужно сделать, это включить следующую зависимость в свойpom
файл Maven :Затем вы применяете исправление (для примера Hibernate + Spring Boot), добавляя
@EnableAutoConfiguration
аннотацию перед классом приложения Spring. Для получения инструкций по установке других настроек и других примеров использования просто обратитесь к github проекта .Хорошо то, что вам вообще не нужно изменять сущности; вы можете оставить их
java.util.Date
поля такими, какие они есть.5.2.2
должен соответствовать используемой вами версии Hibernate. Я не уверен, какую версию вы используете в своем проекте, но полный список предоставленных исправлений доступен на вики-странице github проекта . Причина, по которой исправление отличается для разных версий Hibernate, заключается в том, что создатели Hibernate несколько раз меняли API между выпусками.Внутренне исправление использует подсказки от divestoclimb, Shane и некоторых других источников для создания пользовательского файла
UtcDateType
. Затем он сопоставляет стандартjava.util.Date
с настраиваемым,UtcDateType
который обрабатывает все необходимые часовые пояса. Сопоставление типов достигается с помощью@Typedef
аннотации в предоставленномpackage-info.java
файле.Вы можете найти статью здесь , которая объясняет , почему такой временной сдвиг вообще происходит и каковы подходы к ее решению.
источник
Hibernate не позволяет указывать часовые пояса с помощью аннотаций или любых других средств. Если вы используете Calendar вместо даты, вы можете реализовать обходной путь с помощью свойства HIbernate AccessType и самостоятельно реализовать сопоставление. Более продвинутое решение - реализовать пользовательский тип UserType для сопоставления даты или календаря. Оба решения описаны в моем сообщении в блоге здесь: http://www.joobik.com/2010/11/mapping-dates-and-time-zones-with.html
источник