【问题标题】:How to prevent hibernate from loading wrong dates?如何防止休眠加载错误的日期?
【发布时间】:2016-03-30 17:48:45
【问题描述】:

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

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

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

calendar.getTimeZone().getDisplayName()

返回

Central European Time

BirthDate 列的类型是:

没有时区的生日时间戳

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

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

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

我的数据库版本是

x86_64-unknown-linux-gnu 上的 PostgreSQL 9.4.4,由 gcc (Debian 4.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 - 然后一切似乎都运行良好。但是如何在不改变列数据类型的情况下解决问题呢?你有什么建议吗?

【问题讨论】:

  • PG如何将其存储为时间戳而不是日期?诡异的。您可以更改列定义以将其存储为日期而不是时间戳吗?
  • @NeilMcGuigan 我可以,但是我的数据库中已经有几千个用户,所以我必须更改所有用户的出生日期(我将检查 Date 与 PostgreSQL 中的 Timestamp 有何不同,因为我不太确定如何在这两种类型之间进行转换)。

标签: java hibernate postgresql date tapestry


【解决方案1】:

我认为问题可能在于您的系统设置为CET,但波兰目前在CEST(并且 Pg 尊重 DST)。

你可以做几件事:

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

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

  • 选择时将值转换为timestamptz,因此保留了TZ信息(实际上不确定这个)。

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

要从评论中回答您的问题:您可以将 timestamp/tz 值转换为 date 类型 (birthdate::date)。 dates 没有时间信息并且不依赖于时区,因此您将始终按原样获取值。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-27
    • 2013-08-30
    • 1970-01-01
    • 2019-03-13
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2011-08-11
    相关资源
    最近更新 更多