JPA TemporalType.Date提供错误的日期

wob*_*ogs 11 java mysql jpa

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

@Temporal( TemporalType.DATE )
private Date validFrom;
Run Code Online (Sandbox Code Playgroud)

在我从数据库中提取日期并显示它之前,似乎一切正常.如果我在前端选择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的前端.

Dar*_*gue 26

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

  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的偏移量),但如果在数据库中配置的时间可以将时间转换为不同的时区.默认情况下,大多数数据库默认使用本地服务器时区,这是一个非常糟糕的主意.女士们,先生们......总是以UTC格式存储DATE对象.继续阅读......
  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,即使它们的操作主要发生在某些其他时区.


wob*_*ogs 5

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

<h:outputText value="#{t.validFrom}">
    <f:convertDateTime pattern="dd MMM yyyy"/>
</h:outputText>
Run Code Online (Sandbox Code Playgroud)

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