不需要的自动时区转换使用Hibernate / JPA和JDK日期 [英] Unwanted Automatic Time Zone Conversion Using Hibernate/JPA and JDK Date

查看:704
本文介绍了不需要的自动时区转换使用Hibernate / JPA和JDK日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Hibernate(4.2)作为我的持久性提供者,而且我有一个包含Date字段的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的 DateTime 类的 toDate()方法来获取JDK Date 对象,以便遵守映射:

  public void myMethod (DateTime startDateUTC){
。 。 。
MyTable table = / *获取某种方式* /
table.setStartDate(startDateUTC.toDate());
。 。 。
}

当我在数据库中查看存储的值时,我注意到某处(JDK?Hibernate?)使用代码运行的JVM的默认时区转换Date值。在我的情况下,这是美国/芝加哥。



这个问题真的体现在夏令时间(DST)附近。例如,如果内部时间是

  2014-03-09T02:55:00Z 

它被存储为

  Mar-14 03:55:00 

我想要的是,它被存储为

  09-Mar-14 02:55:00 

但是,在CDT中,3月9日上午2:55不存在(Spring forward)。所以有一些东西(JDK?Hibernate?)正在向前滚动日期。



我希望存储在数据库中的时间是UTC。毕竟,这就是我在内部处理我的应用程序,但是一旦我把它移植到持久化,它将被转换为我的默认时区。



注意:我无法使用设置默认的TimeZone

  TimeZone.setDefault(TimeZone.getTimeZone (UTC))

因为我正在运行的JVM是共享的多个应用程序



如何将日期存储在UTC中,而不将JVM默认时区设置为UTC?

解决方案

我自己碰到了。我所看到的是,即使你已经将UTC指定为Date的时区(可以通过打印出来并看到Z在结尾看到),由于某种原因,JVM希望接管,使用JVM的默认时区转换您的日期。



无论如何,您需要的是一个自定义映射来解决此问题。尝试使用 Jadira

  @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 class将UTC转换为数据库中存储的毫秒值时,将UTC作为时区。你可以指定其他时区,但是听起来像UTC是你想要存储的。



由于你的帖子的评论表明,有时候你用来查询的工具DB正在为您自动地做出无意义的愚蠢自动 - 为什么是我的JDK-default-TZ转换,导致您认为该值仍然不正确。



您可以尝试还要存储原始值(作为INTEGER)只是为了说服你自己存储正确的毫秒值。



HTH,



Mose


I am using Hibernate (4.2) as my persistence provider, and I have a JPA entity that contains a Date field:

@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;
  }
  . . .
}

The column corresponding to START_DATE is defined as START_DATE TIMESTAMP (no time zone).

I am using Joda-Time (2.3) internally to my application to deal with the date (always in UTC), and just prior to persisting the Entity, I use the toDate() method of Joda's DateTime class to get a JDK Date object in order to obey the mapping:

public void myMethod(DateTime startDateUTC) {
  . . .
  MyTable table = /* obtain somehow */
  table.setStartDate(startDateUTC.toDate());
  . . .
}

When I look in the DB at the value that is stored, I notice that somewhere (JDK? Hibernate?) converts the Date value using the default Time Zone of the JVM where the code runs. In my case that is "America/Chicago".

The problem really manifests itself near Daylight Savings Time (DST). For example, if the time internally is

2014-03-09T02:55:00Z

it gets stored as

09-Mar-14 03:55:00

What I would like, is for it to be stored as

09-Mar-14 02:55:00

However, in CDT, 2:55AM on March 9 does not exist ("Spring forward"). So something (JDK? Hibernate?) is rolling the date forward.

I would like for the instant that gets stored in the DB to be in UTC. After all, that's how I am dealing with it internally to my application, but as soon as I hand it off to be persisted, it gets converted to my default time zone.

Note: I am unable to set the default TimeZone using

TimeZone.setDefault(TimeZone.getTimeZone("UTC"))

because the JVM on which I'm running is shared across multiple applications.

How do I store the date in UTC without setting the JVM default Time Zone to UTC?

解决方案

I ran into this myself. What I saw is that even though you've specified UTC as the time zone in your Date (and can see this by printing it out and seeing the 'Z' at the end), for some reason, the JVM wants to take over and convert the date for you using the JVM's default time zone.

Anyway, what you need is a custom mapping to work around this. Try using Jadira:

@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;
  }
  . . .
}

By default Jadira's PersistentDate class uses UTC as the time zone when it converts the date to the millisecond value that gets stored in the DB. You can specify other time zones, but it sounds like UTC is what you want to store.

As the comment to your post suggests, sometimes the tool you use to query the DB is doing the mindlessly stupid automatic-what's-my-JDK-default-TZ based conversion for you, leading you to believe the value is still incorrect.

You may try also to store the raw value (as an INTEGER) just to convince yourself that the correct millisecond value is being stored.

HTH,

Mose

这篇关于不需要的自动时区转换使用Hibernate / JPA和JDK日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆