如何防止hibernate加载错误的日期



问题是我从DAO的加载函数中得到了错误的日期。

观察到的日期存储在PostgreSQL数据库中(来自User表的出生日期列),等于1982-03-28。它有时被认为是1982-03-27。我从更有经验的用户那里得到了一些提示,他们说这在某种程度上与时区问题有关。

错误的值来自java.util.Date类的实例。我通过Calendar类的对象获取它们。当我给这个小家伙打电话时:

calendar.getTimeZone().getDisplayName()

它返回

Central European Time

BirthDate列的类型为:

不带时区的出生日期时间戳

postgresql.conf文件中设置的时区变量的值等于Poland。

加载方法的内部实现如下所示:

public T load(ID aPrimaryKey, boolean aLock)
{
    if (aPrimaryKey == null) {
        throw new IllegalArgumentException("Parameter aPrimaryKey can't be null!");
    }
    preLoad(aPrimaryKey);
    T entity; if (aLock) {
        entity = _session.load(getEntityClass(), aPrimaryKey, LockMode.UPGRADE);
    } else
        entity = _session.load(getEntityClass(), aPrimaryKey);
    postLoad(entity);
    return entity;
}

我的数据库版本是

PostgreSQL 9.4.4 on x86_64-unknown-linux-gnu,由gcc编译(Debian4.9.2-10)4.9.2,64位

我使用

hibernate-core-3.6.0.Final.jar

我的实体类看起来是这样的(还有几个字段):

import javax.persistence.Column;
@javax.persistence.Entity
@javax.persistence.Table(name="User")
@javax.persistence.SequenceGenerator(name="userId", sequenceName="user_id_seq", allocationSize=1)
public class User {
   @javax.persistence.Id
   @Column(name="Id", nullable=false)
   @javax.persistence.GeneratedValue(strategy=javax.persistence.GenerationType.AUTO, generator="userId")
   private long id;
   @Column(name="Name")
   private String firstName;
   public User(String firstName, java.util.Date birthDate, java.util.Date registrationDate)
   {
       this.firstName = firstName;
       this.birthDate = birthDate;
       this.registrationDate = registrationDate;
   }
   @Column(name="BirthDate")
   @javax.persistence.Temporal(javax.persistence.TemporalType.DATE)
   private java.util.Date birthDate;
   @Column(name="RegistrationDate", nullable=false)
   @javax.persistence.Temporal(javax.persistence.TemporalType.TIMESTAMP)
   private java.util.Date registrationDate;
   public String toString()
   {
       return firstName + " should clean himself...";
   }
   public User() {}
}

我将birthdate字段的类型更改为TIMESTAMPTZ,然后一切看起来都很好。但是如何在不改变列的数据类型的情况下解决这个问题呢?你有什么建议吗?

我认为问题可能是您的系统设置为CET,但波兰目前处于CEST(Pg采用夏令时)。

你可以做几件事:

  • 在每次会话开始时使用SET TIME ZONE timezone;,以确保它与您的客户端相匹配。

  • 在选择与客户端匹配的值或函数timezone(zone, timestamp)时使用AT TIME ZONE

  • 选择时将值强制转换为timestamptz,因此TZ信息将被保留(实际上对此不确定)。

但实际上,总是使用timestamptz来存储时间要好得多。

要从注释中回答您的问题:您可以将timestamp/tz值强制转换为date类型(birthdate::date)。date没有时间信息,也不依赖于时区,因此您将始终按原样获得值。

这实际上可能更有意义-您可能确实希望在其原始时区(即用户输入的时区)中查看出生日期,而不是转换为当前TZ。

最新更新