【发布时间】:2015-07-23 20:43:34
【问题描述】:
在我有Timestamp ts = Timestamp.from(instant); 的代码中某处,顾名思义,instant 是java.time.Instant。 (为什么?为了让 Hibernate 4.x 通过UserType 持久化,JDK8 时间类型,在 Hibernate 5 之前尚不支持)。
事实上,让我把代码放上来,这样就清楚了。日志语句就是针对这个问题的。
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
if (value != null){
Timestamp ts = Timestamp.from((Instant) value);
log.info("nullSafeSet from " + value + " (as long: " + ((Instant) value).toEpochMilli() + ") to " + ts + " (as long: " + ts.getTime() + ")");
StandardBasicTypes.TIMESTAMP.nullSafeSet(st, ts, index, session);
} else {
st.setNull(index, Types.TIMESTAMP);
}
}
这就是问题所在。在 Windows(7 位,64 位,尽管这无关紧要)上,时间戳的字符串表示对应于 UTC 值。
From: 2015-05-12T19:00:08.191Z (as long: 1431457208191)
to: 2015-05-12 19:00:08.191 (as long: 1431457208191)
在 *nix(Linux、OS X)上,字符串表示对应于本地(准确地说是 EST,或 EDT)时间:
From: 2015-05-12T19:16:54.488Z (as long: 1431458214488)
to: 2015-05-12 15:16:54.488 (as long: 1431458214488)
绝对时间与可见时间相同。问题是 JDBC 驱动程序向 Oracle 数据库发送到 TIMESTAMP 字段的是字符串表示或等价物(我查看了网络流量,参数是二进制格式,所以不容易弄清楚到底发送了什么)。 同样的代码插入了相当于从 Windows 执行的时间和从 Unix 执行的本地时间的 UTC。
我已经检查了user.timezone 系统属性,在这两种情况下都是America/New York。机器本身也是如此。相同的JDK8版本,相同的应用服务器,相同的代码。
我对这种行为以及如何解决它感到困惑。
【问题讨论】:
-
打印 TimeZone.getDefault() 的值:你可能会有不同的值。
-
@JBNizet 谢谢,确实如此!目前还不清楚为什么,但至少我有解释。
标签: java hibernate timestamp jodatime java-time