【问题标题】:How to assign Date parameters to Hibernate query for current timezone?如何将日期参数分配给当前时区的休眠查询?
【发布时间】:2010-09-22 10:34:30
【问题描述】:

当您将日期分配给命名 SQL 参数时,Hibernate 会自动将其转换为 GMT 时间。你如何让它在所有日期都使用当前服务器时区?

假设您有一个查询:

Query q = session.createQuery("from Table where date_field < :now");
q.setDate("now", new java.util.Date());

"now" 将设置为 GMT 时间,而"new Date()" 获取您当前的服务器时间。

谢谢。

【问题讨论】:

    标签: java hibernate timezone


    【解决方案1】:

    事实证明,Hibernate 不会自动将日期转换为 GMT,如果你使用query.setDate(),它只会切断时间,所以如果你通过“2009-01-16 12:13:14”,它就会变成“2009- 01-16 00:00:00”。

    要考虑到时间,您需要改用query.setTimestamp("date", dateObj)

    【讨论】:

    • 这也让我有点吃不消了。在 Oracle 中 DATE 是与 Java 的 Date 匹配的日期和时间,而 TIMESTAMP 是带有微秒的日期和时间,这无济于事。
    • 现在不推荐使用 Query 类型的方法 setTimestamp(String, Date)
    • 请注意,这是因为它不能 - java.util.Date 结构不包含任何时区信息,它只是自纪元以来的毫秒数。因此,如果您希望 Hibernate 将您的无时区 Date 转换为 GMT,您还需要告诉它 您的日期与 UTC 纪元相差多远
    【解决方案2】:

    Hibernate 不知道时区。任何时区转换都应在执行查询之前完成。

    例如,如果您的数据库服务器设置为 CST,但用户使用的是 EST,则您需要将 1 小时添加到作为查询输入的任何时间戳。

    【讨论】:

      【解决方案3】:

      我们使用自定义的休眠日期类型。每当我们在查询上设置参数时,我们都会使用基类或实用程序方法,这样我们就可以将用户的时区传递给自定义类型参数。

      您可以通过手动调整实用程序方法中查询的时间来解决问题,但是这样读取或写入数据库的日期也可以正确转换。此方法还处理数据库将日期存储在其本地时区的情况。因此,即使您在一个时区有一个用户,在另一个时区有一个数据库服务器,并且 Java 使用 GMT,它也可以让一切变得简单。它最终看起来像:

      Properties properties = new Properties();
      properties.setProperty("timeZone", databaseTimeZone);
      query.setParameter("from", dateEnteredByUser, Hibernate.custom(LocalizedDateType.class, properties));
      

      作为额外的奖励,我们使用它来处理 SQL Server 将 23:59:59.999 转换为第二天的事实。在自定义类型中,我们会检查并取消它。

      【讨论】:

        【解决方案4】:

        如果您需要 timeZone 同步值,您可以在 HQL 中使用 now()。另外我建议你使用 Joda 库。它有一个休眠插件模块。

        【讨论】:

          【解决方案5】:

          Hibernate 团队已弃用 setTimestamp(String name, Date val) 方法以及 org.hibernate.Query 接口自版本 5.2

           /* @deprecated (since 5.2) use {@link #setParameter(int, Object)} or
              {@link #setParameter(int, Object, Type)}  instead
           */
          

          所以你可以使用下面的代码:

          import org.hibernate.query.Query;
          ...
          Query query = session.createQuery("from Table where date_field < :now");
          query.setParameter("now", new Date(), TimestampType.INSTANCE );
          

          值得注意的是,减少时间部分的 setDate 方法也已弃用,可以用此选项替换(来自同一接口 org.hibernate.query.Query) :

          query.setParameter("firstMomentOfToday", new Date(), DateType.INSTANCE);
          

          如果您打算将它与 java 8 和相关的 jdbc 驱动程序(如 Oracle 'ojdbc8.jar' 和支持的休眠版本一起使用,这可能无法按预期工作,因此使用新的 java 是明智之举.time.LocalDate 和 LocalDateTime 代替。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-04-17
            • 2011-11-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-12-17
            • 1970-01-01
            相关资源
            最近更新 更多