Java 为什么我的时间戳在时区中移动?
我在PostgreSQL 9.1数据库中的Java 为什么我的时间戳在时区中移动?,java,hibernate,postgresql,jpa,timestamp,Java,Hibernate,Postgresql,Jpa,Timestamp,我在PostgreSQL 9.1数据库中的时间戳(无时区)列中有此日期: 2012-11-17 13:00:00 它应该是UTC格式的,我已经选择它作为UNIX时间戳(EXTRACT epoch)进行了验证 然而,当我使用JPA/Hibernate阅读这个日期时,事情就出了问题。这是我的映射: @Column(nullable=true,updatable=true,name="startDate") @Temporal(TemporalType.TIMESTAMP) private Date
时间戳(无时区)列中有此日期:
2012-11-17 13:00:00
它应该是UTC格式的,我已经选择它作为UNIX时间戳(EXTRACT epoch
)进行了验证
然而,当我使用JPA/Hibernate阅读这个日期时,事情就出了问题。这是我的映射:
@Column(nullable=true,updatable=true,name="startDate")
@Temporal(TemporalType.TIMESTAMP)
private Date start;
然而,我得到的日期是:
2012年11月17日格林尼治标准时间12:00:00
为什么会发生这种情况,更重要的是,我如何才能阻止它
请注意,我只想普遍地存储时间点(正如java.util.Date
所做的那样),我对时区毫不关心,只是我显然不希望它们破坏我的数据
正如您可能推断的那样,连接到数据库的客户端应用程序是UTC+1(荷兰)
此外,Hibernate在自动生成模式时选择了不带时区的列类型timestamp
。是否应该改为带时区的时间戳?我发现将列类型更改为带时区的时间戳可以解决问题。我还必须将所有其他时间戳列转换为该列
由此我得出结论,Hibernate不像UTC那样读取没有时区的时间戳
列,而是像本地时区一样读取。如果有办法将其解释为UTC,请让我知道。如果数据库不提供时区信息,则JDBC驱动程序应将其视为JVM的本地时区(请参阅):
使用运行应用程序的虚拟机的默认时区将指定参数设置为给定的java.sql.Date值
Javadoc和JDBC规范没有明确说明任何关于ResultSet
等的内容,但为了保持一致,大多数驱动程序也会将该规则应用于从数据库检索的日期。如果希望对所使用的时区进行明确控制,则需要使用各种set/getDate/Time/Timestamp
方法,这些方法也接受正确时区中的Calendar
对象
某些驱动程序还提供连接属性,允许您指定在与数据库进行转换时使用的时区。有几种解决方案可以解决这些问题:
1) 最简单的方法是在JDBC连接字符串中设置时区,只要数据库支持
对于MySQL,您可以使用useGmtMillisForDatetimes=true
强制在数据库中使用UTC。据我所知,Postgres不支持这样的选项,但我可能错了,因为我不使用Postgres
2) 使用设置Java客户端程序中的默认时区
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
缺点:如果你的程序有一个UI部件,你也可以在你不想要的地方改变时区
3) 仅对Hibernate使用带有特殊getter的映射:
在映射文件中
<property name="myTimeWithTzConversion" type="timestamp" access="property">
<column name="..." />
</property>
在您的程序中,您有get/setMyTimeWithTzConversion()
,只允许hibernate访问成员变量Timestamp myTime
,在这个getter/setter中,您可以进行时区转换
我们最终决定使用3(这是一项稍微多一些的编程工作),因为在那里我们不必更改现有的数据库,我们的数据库是UTC+1(这禁止使用JDBC连接字符串解决方案),并且不会干扰现有的UI 我认为将无时区时间戳
读取为本地时区是Java/JDBC的事情。根据当前时区解释无时区时间戳
是普遍正确的方法!没什么特别的。可能有助于理解。@ErwinBrandstetter不,没有时区的时间戳是UTC,因为数据库没有“当前”时区,因为它是数据存储,不是暂时的。
<property name="myTimeWithTzConversion" type="timestamp" access="property">
<column name="..." />
</property>