我使用Hibernate (4.2)作为我的持久性提供程序,并且我有一个包含日期字段的JPA实体:
@Entity
@Table(name = "MY_TABLE")
public class MyTable implements Serializable {
. . .
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "START_DATE")
private Date startDate;
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
. . .
}
与START_DATE对应的列被定义为START_DATE TIMESTAMP
(无时区)。
我在应用程序内部使用Joda-Time (2.3)来处理日期(总是在UTC中),并且在持久化实体之前,我使用Joda的toDate()
类的DateTime
方法来获取JDK Date
对象,以便遵循映射:
public void myMethod(DateTime startDateUTC) {
. . .
MyTable table = /* obtain somehow */
table.setStartDate(startDateUTC.toDate());
. . .
}
当我在DB中查看存储的值时,我注意到某个地方(JDK?冬眠?)使用运行代码的JVM的默认时区转换日期值。我的例子是“美国/芝加哥”。
这个问题在夏令储蓄时间(DST)附近确实表现出来。例如,如果内部时间是
2014-03-09T02:55:00Z
它被存储为
09-Mar-14 03:55:00
我想要的是,把它作为
09-Mar-14 02:55:00
然而,在CDT中,3月9日凌晨2:55分并不存在("Spring forward")。所以有什么(JDK?冬眠?)把日期提前了。
我希望存储在DB中的瞬间处于UTC中。毕竟,这就是我在内部处理它给我的应用程序的方式,但是一旦我把它交给持久化,它就会被转换成我的默认时区。
注意:我无法使用设置默认的TimeZone
TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
,因为我正在运行的JVM是跨多个应用程序共享的.
如何在不将JVM默认时区设置为UTC的情况下将日期存储在UTC中?
发布于 2014-03-06 20:51:18
我自己也碰到这个的。我看到的是,即使您在日期中将UTC指定为时区(并且可以通过打印出来并在末尾看到'Z‘来查看它),但出于某种原因,JVM希望使用JVM的默认时区来接管和转换日期。
无论如何,您需要的是一个自定义映射来解决这个问题。尝试使用贾迪拉
@Entity
@Table(name = "MY_TABLE")
public class MyTable implements Serializable {
. . .
@Column(name = "START_DATE")
@Type(type="org.jadira.usertype.dateandtime.legacyjdk.PersistentDate")
private Date startDate;
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
. . .
}
默认情况下,Jadira的PersistentDate
类在将日期转换为存储在DB中的毫秒值时使用UTC作为时区。您可以指定其他时区,但听起来像是要存储UTC。
正如您的帖子中的注释所示,有时您用来查询DB的工具是对您进行愚蠢的自动--我的--默认-基于TZ的基于TZ的转换,这使您相信这个值仍然是不正确的。
您还可以尝试存储原始值(作为整数),以使自己确信正在存储正确的毫秒值。
HTH,
莫西
发布于 2016-11-08 12:47:55
有一篇关于这个意外时区移位问题的文章,您可以查看这里。它为问题的根源提供了解释,并说明了如何处理它。当然,主要的假设是我们希望将日期作为UTC存储在数据库中。
例如,每当您从数据库中读取日期(假设: 9:54 UTC)时,JDBC跳过有关时区的任何信息。因此,JVM通过JDBC接收到的是一个日期,它被解释为它位于本地时区(对于我的例子来说,是9:54 UTC+2)。如果本地时区与UTC不同(通常是这样),我们将以不正确的时移结束。
在写入数据库时也会发生类似的情况。
有一个小型开源项目DbAssist为不同版本的Hibernate提供修复。因此,如果您正在使用Hibernate 4.2.21,只需在POM文件中添加以下Maven依赖项,您的问题就解决了(可以在库github上找到安装的详细说明,例如Spring )。
<dependency>
<groupId>com.montrosesoftware</groupId>
<artifactId>DbAssist-4.2.21</artifactId>
<version>1.0-RELEASE</version>
</dependency>
应用此修复后,实体类中的java.util.Date
字段将按预期的方式读取和持久化:就好像它们作为UTC存储在数据库中一样。如果使用JPA注释,则不必更改实体中的映射(如前面的响应之一);它是自动完成的。
在内部,修补程序使用自定义UTC日期类型,该类型覆盖Hibernate的日期类型,以强制它将DB中的所有日期视为UTC。然后,为了应用从java.util.Date
到UtcDateType
的映射,它使用了@Typedef
注释。见下文:
@TypeDef(name = "UtcDateType", defaultForType = Date.class, typeClass = UtcDateType.class),
package com.montrosesoftware.dbassist.types;
如果您的项目依赖Hibernate HBM文件或其他版本的Hibernate,请访问项目的github wiki,了解如何安装正确的修补程序。
发布于 2014-03-05 22:28:54
您试过从getDateTime对象中使用DateTime (DateTimeZone x)吗?
就像这样:
public void myMethod(DateTime startDateUTC) {
. . .
MyTable table = /* obtain somehow */
table.setStartDate(startDateUTC.toDateTime(DateTimeZone.UTC));
. . .
}
希望它能帮到你!
https://stackoverflow.com/questions/22210570
复制相似问题