Hibernate 在将 Java 日历对象读取和写入 SQL TIMESTAMP 时使用哪个时区?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4117249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What time zone does Hibernate use when it reads and writes a Java Calendar object to an SQL TIMESTAMP?
提问by Derek Mahar
When Hibernatewritesa Java Calendar
object to an SQL TIMESTAMP
column, to which time zone does it adjust the date, that of the computer or that specified in the calendar object (or some other)?
当Hibernate将JavaCalendar
对象写入SQLTIMESTAMP
列时,它会将日期、计算机的日期或日历对象(或其他一些)中指定的日期调整到哪个时区?
When Hibernate readsthe TIMESTAMP
into the calendar object, to which time zone does it translate the date?
当Hibernate读的TIMESTAMP
到日历对象,以哪个时区并把它翻译的日期?
采纳答案by Pascal Thivent
When Hibernate writes a Java Calendar object to an SQL TIMESTAMP column, to which time zone does it adjust the date, that of the computer or that specified in the calendar object (or some other)?
当 Hibernate 将 Java 日历对象写入 SQL TIMESTAMP 列时,它会将日期、计算机的日期或日历对象(或其他一些)中指定的日期调整到哪个时区?
Hiberante 3.x uses the following in the CalendarType
(see HB-1006):
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 );
}
So Hibernate uses PreparedStatement#setTimestamp(int, Timestamp, Calendar)
which uses the time zone of the calendar.
所以 Hibernate 使用PreparedStatement#setTimestamp(int, Timestamp, Calendar)
which 使用日历的时区。
When Hibernate reads the TIMESTAMP into the calendar object, to which time zone does it translate the date?
当 Hibernate 将 TIMESTAMP 读入日历对象时,它会将日期转换到哪个时区?
Well, again, let's look at the CalendarType
class:
好吧,再一次,让我们看一下这个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;
}
}
So Hibernate constructs a default GregorianCalendar
using the current time in the default time zonewith the default locale.
因此 Hibernate使用默认时区中的当前时间和默认 locale构造了一个默认值GregorianCalendar
。
As a side note, I highly suggest to read the following question:
作为旁注,我强烈建议阅读以下问题:
回答by markthegrea
I just spent 6 hours on a similar issue and thought I would document it here. Hibernate indeed does use the JVM timezone but it can be changed by extending the CalendarType like this:
我刚刚在一个类似的问题上花了 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);
}
}
the secret sauce here is :
这里的秘诀是:
rs.getTimestamp(name, new GregorianCalendar(UTC));
This converts the timezone from the result set to whatever timezone you want. So what I did was use this type with any UTC calendars and the standard Hibernate type for the local time. Works slick as a whistle...
这会将时区从结果集中转换为您想要的任何时区。所以我所做的是将这种类型与任何 UTC 日历和本地时间的标准 Hibernate 类型一起使用。像哨子一样光滑......
回答by orim
If you don't want to write the code yourself, you can just use the open source library DbAssist
. After applying this fix, the dates in the database will be treated by JDBC and then Hibernate as UTC, so you do not even have to change your entitiy classes.
如果不想自己写代码,可以直接使用开源库DbAssist
。应用此修复程序后,数据库中的日期将被 JDBC 处理,然后被 Hibernate 视为 UTC,因此您甚至不必更改您的实体类。
For example, if you are using JPA Annotations with Hibernate 4.3.11, add the following Maven dependency:
例如,如果您在 Hibernate 4.3.11 中使用 JPA Annotations,请添加以下 Maven 依赖项:
<dependency>
<groupId>com.montrosesoftware</groupId>
<artifactId>DbAssist-4.3.11</artifactId>
<version>1.0-RELEASE</version>
</dependency>
Then you just apply the fix:
然后你只需应用修复:
For Hibernate + Spring Boot setup, add the @EnableAutoConfiguration
annotation before the application class.
对于 Hibernate + Spring Boot 设置,@EnableAutoConfiguration
在应用程序类之前添加注解。
For HBM files, you have to change the entity mapping files to map Date
types to the custom one:
对于 HBM 文件,您必须更改实体映射文件以将Date
类型映射到自定义类型:
<property name="createdAt" type="com.montrosesoftware.dbassist.types.UtcDateType" column="created_at"/>
If you want to learn more about how to apply the fix for different Hibernate versions (or HBM files), refer to the project's github. You can also read more about the time zone shift issue in this article.
如果您想了解有关如何为不同的 Hibernate 版本(或 HBM 文件)应用此修复程序的更多信息,请参阅项目的 github。您还可以在本文中阅读有关时区偏移问题的更多信息。
回答by Vlad Mihalcea
By default, it's up to the JDBC Driver to decide what timezone to use. Typically, the JVM time zone is used unless you configure the JDBC Driver to use a custom time zone.
默认情况下,由 JDBC 驱动程序决定使用哪个时区。通常,除非您将 JDBC 驱动程序配置为使用自定义时区,否则将使用 JVM 时区。
If you want to control what time zone is used, you can set the time zone at the JVM level. If you want the JVM time zone to differ from the one used by the database, then you need to use the following Hibernate 5.2 configuration property:
如果要控制使用什么时区,可以在JVM级别设置时区。如果您希望 JVM 时区与数据库使用的时区不同,则需要使用以下 Hibernate 5.2 配置属性:
<property name="hibernate.jdbc.time_zone" value="US/Eastern"/>
For more details, check out this article.
有关更多详细信息,请查看这篇文章。