JPA TemporalType.Date提供错误的日期

我有一个类,其日期字段表示一段数据的“有效起始日期”。 它的定义如下:

@Temporal( TemporalType.DATE ) private Date validFrom; 

在我从数据库中提取日期并显示它之前,似乎一切正常。 如果我在前端选择2003年9月18日的日期,那么当我在数据库中检查确定的日期是保留的日期时保存它(数据库是MySQL 5.5.9列类型是DATE)。 然而,当我拉出一份清单时,显示的日期是2003年9月17日 – 前一天。

如果我选择在2003年3月26日或2003年12月25日之前或之后的一个日期,一切都很好,所以我猜这是与夏令时有关但错误在哪里蔓延? 由于数据库似乎保持正确的日期,我猜测它必须在JPA转换回java.util.Date时 – java.util.Date是用于日期的最佳类吗? 我已经看过一些人们使用Calendar的例子,但这看起来非常重,我不确定它能用于基于JSF的前端。

很抱歉,到目前为止所有答案通常都是不正确的。 答案很简单,但要求我们将五点分开:

  1. DATE = java.sql.Date,它是java.util.Date的包装器,它是UTC时区中自Epoch以来的毫秒数。 因此,这具有固定GMT + 0(UTC)时区中的年/月/日/小时/分/秒。 但请注意,java.sql.Date将时间组件设置为零!
  2. TIMESTAMP = java.sql.TimeStamp是Date的组件包装器,它添加小数秒以支持SQL DATE类型标准。 此类/类型与此问题无关或不需要,但简而言之,它具有日期加上时间。
  3. 数据库按照定义存储DATE对象(使用UTC作为Java的偏移量),但如果在数据库中配置的时间可以将时间转换为不同的时区。 默认情况下,大多数数据库默认使用本地服务器时区,这是一个非常糟糕的主意。 女士们,先生们……总是将DATE对象存储在UTC中。 继续阅读……
  4. JVM和时区中的时间必须正确。 由于Date对象使用UTC,是否为您的服务器时间计算了偏移量? 考虑到强烈建议将服务器时间设置为GMT + 0(UTC)。
  5. 最后,当我们想要从数据库渲染DATE时(使用JSF或其他),它应该设置为GMT + 0时区,如果从服务器上方也完成…你的日期和时间总是一致的,参考和所有好事。 剩下的就是渲染时间,这就是用户代理(例如网络应用程序) 用于将GMT + 0时间转换为用户“本地”时区的地方。

简介:在服务器上,数据库中,在Java对象中使用UTC(GMT + 0)。

DATE和TIMESTAMP仅与数据库视角不同,因为TIMESTAMP携带额外的秒数。 两者都使用GMT + 0(隐含)。 JodaTime是一个首选的日历框架来处理所有这些,但不会解决不匹配的JVM到数据库时区设置的问题。

如果从JVM到数据库的应用程序设计不使用GMT,由于日光节省,时钟调整以及在世界本地时钟中播放的各种其他区域游戏……交易时间和其他一切将永远扭曲,非参考,不一致等

关于数据类型的另一个很好的相关答案: java.util.Date vs java.sql.Date

另请注意,Java 8具有更好的日期/时间处理(最终),但这并不能解决JVM运行的服务器时钟在一个时区中而数据库在另一个时区中的情况。 此时总会发生翻译。 在我使用的每个大型(智能)客户端中,由于这个原因,数据库和JVM服务器时区设置为UTC,即使它们的操作主要发生在某些其他时区。

经过大量的实验和搜索,我很确定我找到了问题的原因。 日期保存在java.util.Date中,该日期包含所有时间和时区的行李。 似乎JPA正在从数据库中读取2003年9月18日的日期,然后像这样填写日期:“Thu Sep 18 00:00:00 BST 2003” – 注意时区已设置为BST可能因为它不是由数据库显式设置。 无论如何,如果你只想看到这样的日期,有必要格式化JSF页面中的输出:

    

但是,这假定时区是机器上当前有效的任何时区。 在我的情况下,时区目前是格林威治标准时间(因为它是冬天)所以当提交日期“星期四9月18日00:00:00 BST 2003”时,它将它转换为GMT,减去一个小时,显示器显示2003年9月17日。

但是使用DATETIME而不是日期将导致一小时(更多取决于时区)差异,如果您处理日期而不是时间值,则可以忽略。 对我来说,来自mysql数据库的数据是正确的值,但是当使用没有timeZone参数的f:convertDateTime时会出现差异,导致使用GMT的默认值!

    

工作正常,但我认为当我们切换到CEST时,这将不再有效….

我有同样的问题。 不知道原因,但我的解决方法如下:

在数据库中,我将列类型从DATE更改为DATETIME

在实体类中,我更改了@Temporal注释,但保留了数据类型Date

 @Temporal(TemporalType.TIMESTAMP) private Date myDate; 

我遇到了同样的问题,但我使用JSF 2作为前端。 如果您正在使用JSF组件,请查看此其他stackoverflow讨论,并看到JSF 2无法按预期的TimeZone规则播放。 设计师实施它以始终使用GMT。 在我的情况下,这导致我的日期在数据库中关闭了5或6个小时,但显示正确。

JSF convertDateTime呈现前一天

与SQL Server有同样的问题。 问题是旧的SQL JDBC驱动程序。 从2010年4月开始sqljdbc4.jar与SQL 2000兼容,并且日期有一两天的问题。 然后更新到最新的驱动程序,甚至从2012年更新到一个,问题就消失了。