我有一个类,其日期字段表示一段数据的“有效起始日期”。它的定义如下:
@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的前端。
答案 0 :(得分:24)
非常抱歉,到目前为止所有答案通常都是错误的。 答案很简单,但要求我们将五点分开:
摘要:在服务器上,数据库中,在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,即使它们的操作主要发生在其他某个时区。
答案 1 :(得分: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>
然而,这假设时区是机器上当前有效的任何时区。在我的情况下,时区目前是格林尼治标准时间(因为它是冬天),所以当提交日期“星期四9月18日00:00:00 BST 2003”时,它将其转换为GMT,减去一小时,显示器显示在2003年9月17日。
答案 2 :(得分:2)
但是使用DATETIME而不是日期将导致一小时(更多取决于时区)差异,如果您处理日期而不是时间值,则可以忽略。 对我来说,来自mysql数据库的数据是正确的值,但是当使用没有timeZone参数的f:convertDateTime时会出现差异,导致默认使用GMT!
<h:outputText value="#{test.dt}">
<f:convertDateTime pattern="yyyy-MM-dd HH:mm:ss" timeZone="CET"/>
</h:outputText>
工作正常,但我认为当我们切换到CEST时,这将不再有效....
答案 3 :(得分:1)
我遇到了同样的问题。不知道原因,但我的解决方法如下:
在数据库中,我将列类型从DATE
更改为DATETIME
。
在实体类中,我更改了@Temporal
注释但保留了数据类型Date
:
@Temporal(TemporalType.TIMESTAMP)
private Date myDate;
答案 4 :(得分:1)
我遇到了同样的问题,但我使用JSF 2作为前端。如果您正在使用JSF组件,请查看此其他stackoverflow讨论,并查看JSF 2无法按预期的TimeZone规则播放。设计师实施它以始终使用GMT。在我的情况下,这导致我的日期在数据库中关闭了5或6个小时,但显示正确。
答案 5 :(得分:0)
与SQL Server有同样的问题。问题是旧的SQL JDBC驱动程序。从2010年4月开始,sqljdbc4.jar与SQL 2000兼容,并且日期有一两天的问题。 然后更新到最新的驱动程序,甚至从2012年更新到一个,问题就消失了。