Какой часовой пояс использует Hibernate, когда он читает и записывает объект Java Calendar в SQL TIMESTAMP?

Когда Hibernate записывает объект Java Calendar в столбец SQL TIMESTAMP , на какой часовой пояс он настраивает дату, дату или компьютер, указанный в объекте календаря (или какой-либо другой)?

Когда Hibernate считывает TIMESTAMP в объект календаря, к которому этот временной интервал переводит дату?

Когда Hibernate записывает объект Java Calendar в столбец SQL TIMESTAMP, на какой часовой пояс он настраивает дату, дату или компьютер, указанный в объекте календаря (или какой-либо другой)?

Hiberante 3.x использует следующее в CalendarType (см. HB-1006 ):

 public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { final Calendar cal = (Calendar) value; //st.setTimestamp( index, new Timestamp( cal.getTimeInMillis() ), cal ); //JDK 1.5 only st.setTimestamp( index, new Timestamp( cal.getTime().getTime() ), cal ); } 

Таким образом, Hibernate использует PreparedStatement#setTimestamp(int, Timestamp, Calendar) который использует часовой пояс календаря.

Когда Hibernate считывает TIMESTAMP в объект календаря, к которому этот временной интервал переводит дату?

Ну, опять же, давайте посмотрим на класс CalendarType :

 public Object get(ResultSet rs, String name) throws HibernateException, SQLException { Timestamp ts = rs.getTimestamp(name); if (ts!=null) { Calendar cal = new GregorianCalendar(); if ( Environment.jvmHasTimestampBug() ) { cal.setTime( new Date( ts.getTime() + ts.getNanos() / 1000000 ) ); } else { cal.setTime(ts); } return cal; } else { return null; } } 

Таким образом, Hibernate создает GregorianCalendar умолчанию, используя текущее время в часовом поясе по умолчанию с локалью по умолчанию .


В качестве примечания я настоятельно рекомендую прочитать следующий вопрос:

  • Переход на летнее время и передовые методы часового пояса

Я просто провел 6 часов по аналогичной проблеме и подумал, что я зарегистрирую ее здесь. Hibernate действительно использует часовой пояс JVM, но его можно изменить, расширив CalendarType следующим образом:

 public class UTCCalendarType extends CalendarType { private static final TimeZone UTC = TimeZone.getTimeZone("UTC"); /** * This is the original code from the class, with two changes. First we pull * it out of the result set with an example Calendar. Second, we set the new * calendar up in UTC. */ @Override public Object get(ResultSet rs, String name) throws SQLException { Timestamp ts = rs.getTimestamp(name, new GregorianCalendar(UTC)); if (ts != null) { Calendar cal = new GregorianCalendar(UTC); cal.setTime(ts); return cal; } else { return null; } } @Override public void set(PreparedStatement st, Object value, int index) throws SQLException { final Calendar cal = (Calendar) value; cal.setTimeZone(UTC); st.setTimestamp(index, new Timestamp(cal.getTime().getTime()), cal); } } 

секретный соус здесь:

  rs.getTimestamp(name, new GregorianCalendar(UTC)); 

Это преобразует часовой пояс из набора результатов в любой часовой пояс, который вы хотите. Так что я использовал этот тип с любыми календарем UTC и стандартным типом Hibernate для местного времени. Работает гладко, как свисток …

По умолчанию драйвер JDBC должен решить, какой часовой пояс использовать. Как правило, часовой пояс JVM используется, если вы не настроили Драйвер JDBC для использования пользовательского часового пояса.

Если вы хотите контролировать, какой часовой пояс используется, вы можете установить часовой пояс на уровне JVM. Если вы хотите, чтобы часовой пояс JVM отличался от того, который используется в базе данных, вам необходимо использовать следующее свойство конфигурации Hibernate 5.2:

 <property name="hibernate.jdbc.time_zone" value="US/Eastern"/> 

Для получения дополнительной информации ознакомьтесь с этой статьей .

Если вы не хотите писать код самостоятельно, вы можете просто использовать библиотеку с открытым исходным кодом DbAssist . После применения этого исправления даты в базе данных будут обрабатываться JDBC, а затем Hibernate в качестве UTC, поэтому вам даже не придется менять свои классы entitiy.

Например, если вы используете JPA-аннотации с Hibernate 4.3.11, добавьте следующую зависимость Maven:

 <dependency> <groupId>com.montrosesoftware</groupId> <artifactId>DbAssist-4.3.11</artifactId> <version>1.0-RELEASE</version> </dependency> 

Затем вы просто применяете исправление:

Для настройки Hibernate + Spring Boot добавьте аннотацию @EnableAutoConfiguration до класса приложения.

Для файлов HBM вам необходимо изменить файлы сопоставления сущностей для сопоставления типов Date с пользовательским:

 <property name="createdAt" type="com.montrosesoftware.dbassist.types.UtcDateType" column="created_at"/> 

Если вы хотите узнать больше о том, как применить исправление для разных версий Hibernate (или файлов HBM), обратитесь к github проекта . Вы также можете узнать больше о проблеме изменения часового пояса в этой статье .