【问题标题】:Java Daylight saving and HibernateJava 夏令时和休眠
【发布时间】:2016-11-25 04:14:54
【问题描述】:

我找到了一种使用 UTC 时区创建我想要的日期的方法: Java Date and Daylight Saving

所以我可以创建“Sun Mar 25 02:00:00”,但是当我在 Hibernate 中插入这个日期时,它没有写入它,似乎 hibernate 使用了一个我无法覆盖的不同时区。

我的问题是,如果我使用 UTC 时区,我也无法在我的 Hibernate/H2 数据库中插入这个日期:“Sun Mar 25 02:00:00”。

更新 1: 我正在尝试插入这些值:

Sun Mar 25 01:00:00 UTC 2012
Sun Mar 25 02:00:00 UTC 2012
Sun Mar 25 03:00:00 UTC 2012
Sun Mar 25 04:00:00 UTC 2012
Sun Mar 25 05:00:00 UTC 2012
Sun Mar 25 06:00:00 UTC 2012
Sun Mar 25 07:00:00 UTC 2012
Sun Mar 25 08:00:00 UTC 2012
Sun Mar 25 09:00:00 UTC 2012
Sun Mar 25 10:00:00 UTC 2012
Sun Mar 25 11:00:00 UTC 2012
Sun Mar 25 12:00:00 UTC 2012
Sun Mar 25 13:00:00 UTC 2012
Sun Mar 25 14:00:00 UTC 2012
Sun Mar 25 15:00:00 UTC 2012
Sun Mar 25 16:00:00 UTC 2012
Sun Mar 25 17:00:00 UTC 2012
Sun Mar 25 18:00:00 UTC 2012
Sun Mar 25 19:00:00 UTC 2012
Sun Mar 25 20:00:00 UTC 2012
Sun Mar 25 21:00:00 UTC 2012
Sun Mar 25 22:00:00 UTC 2012
Sun Mar 25 23:00:00 UTC 2012

但在数据库中有这些:

【问题讨论】:

  • 从这个问题和你的另一个问题中仍然不清楚哪个你想要凌晨 2 点。世界标准时间凌晨 2 点?或者在某个本地时区凌晨 2 点?你说你不能插入值 - 当你尝试时会发生什么?
  • 已更新。时区并不重要,我会插入“Sun Mar 25 02:00:00 2012”,但它不起作用。
  • 时区绝对很重要。您的数据库本身是否有任何时区设置?
  • 也许这就是问题所在。我正在使用 Hibernate 和 H2,我没有找到任何设置数据库时区的选项
  • 如何插入数据,如何查询数据?根据使用的方法,将调整小时,因为时间不存在。如果您使用 java.util.Date / java.sql.Timestamp,就会发生这种情况。如果您将数据作为字符串插入和读取,则不会对 H2 的最新版本进行任何调整,因为在内部,H2 不再使用 java.util.Calendar / java.util.Date / java.sql.Date/Time/Timestamp(正是因为这个原因)。跨度>

标签: java hibernate h2 dts


【解决方案1】:

这是 JDBC 的“特性”,而不是 Hibernate。因此,您可以在 jdbc 选项(hibernate.cfg.xml 中的 jdbc 连接字符串)中而不是在 Hibernate 选项中更改此行为。默认情况下,日期值始终保存在客户端应用程序的时区中(而不是数据库的时区,因为它似乎更符合逻辑)。例如,MySQL 知道一个 jdbc 连接选项,它强制数据库始终以 UTC 存储日期值。我不知道H2是否知道这样的选择,可能不会。

在您的示例中,3 月 25 日是您的白天时间的第一天。 3 月 25 日 02:00 在您的时区中不存在,这就是您在数据库中找不到它的原因。

如果您不想要连接字符串中的选项(其缺点可能并非在所有数据库上都可用),那么有三种可能的方法来解决该问题:

  1. 在插入之前和阅读之后,您在程序中进行时区对话。为此,除了您的普通 getter get/setMyTime() 之外,您还为 Hibernate get/setHibernateMyTime() 编写了一个额外的 getter 和 setter,您可以在其中进行时区转换,并在映射文件或注释中使用它们。对于时区转换,您可以使用 TimeZone.getOffset()。

  2. 使用字符串而不是日期。在这种情况下,您不需要进行时区转换,但您必须将字符串转换为日期,反之亦然。

  3. 以 UTC 作为本地时间运行应用程序。如果在任何地方都需要用户的本地时间,例如在用户界面中,这将有缺点。

我们在应用程序中做了解决方案 1。

【讨论】:

    【解决方案2】:

    正如 Johanna 所提到的,有几种方法可以处理这个时区偏移问题。还有一篇文章更详细地解释了这个问题,提供了更多的例子和解决方案。

    考虑到上一个答案中的选项 1 并且您不想自己编写所有代码,您可以使用一个小型开源库 DbAssist 。它将java.util.Datejava.util.Timestamp 映射到自定义UtcDateType,该UtcDateType 在内部覆盖setter 和getter,以便在读取或写入数据库时​​将数据库中的日期视为UTC 时区。这是一个方便的解决方案,因为您根本不需要更改实体类。

    您所要做的就是添加依赖项(将 5.2.2 替换为您的 Hibernate 版本):

    <dependency>
        <groupId>com.montrosesoftware</groupId>
        <artifactId>DbAssist-5.2.2</artifactId>
        <version>1.0-RELEASE</version>
    </dependency>
    

    然后按照项目github 的安装指南中的说明应用修复程序。我不是在这里复制它,因为它会根据您是使用 JPA 注释还是 HBM 文件来映射您的实体字段而有所不同;不过,这是一个简单的单线设置。

    【讨论】:

      【解决方案3】:

      你能解释一下你的表的数据结构吗?您在为该列使用 DATETIME 还是 TIMESTAMP?

      根据 MySQL 官方文档 - MySQL 将 TIMESTAMP 值从当前时区转换为 UTC 进行存储,然后从 UTC 转换回当前时区进行检索。它使用 JDBC 连接的当前时区进行此转换。

      这种行为很奇怪但正确,“Sun Mar 25 02:00:00”在您的时区(可能是欧洲中部)不存在。如果您需要保存该日期,您可以将列创建为 DATETIME。

      【讨论】:

        猜你喜欢
        • 2012-10-22
        • 2011-12-22
        • 2011-08-01
        • 2012-12-21
        • 2011-02-25
        • 1970-01-01
        • 1970-01-01
        • 2018-07-06
        • 2018-03-12
        相关资源
        最近更新 更多