Java 程序在错误时区的 HSQLDB 中的 UTC Unix 时间戳存储

UTC Unix timestamp storage in HSQLDB from Java program in wrong timezone

我正在尝试了解如何存储 Unix timestamp (that is, a number of seconds since 1970 expressed in the UTC/GMT timezone) inside an HSQLDB 嵌入式文件数据库。但是,我还没有理解 TZ 处理如何与 HSQL 一起工作。

我的程序将在不同的区域使用,因此必须使用 UTC。此外,我无法更改默认时区(与 java.util.TimeZone.setDefault 一样),因为它将嵌入到其他程序中,因此不应更改环境。

我的尝试 - 文档指出:

When datetime values are sent to the database using the PreparedStatement or CallableStatement interfaces, the Java object is converted to the type of the prepared or callable statement parameter. This type may be DATE, TIME, or TIMESTAMP (with or without time zone). The time zone displacement is the time zone of the JDBC session.

所以我在数据库中使用了一个 TIMESTAMP 列(没有时区 - 默认值),然后发出 SET TIME ZONE INTERVAL '0:00' HOUR TO MINUTE(将会话置于 UTC TZ)然后 INSERT INTO TEST VALUES(?) 与?作为包含正确 Unix 值的 Java 时间戳对象(GMT 相关,测试正常)。

遗憾的是,在这种情况下,数据库的 SQL 日志显示时间戳已恢复为我的本地时区 (+2)。对于时间戳 1442132237635(UTC 为 8H17,+2 为 10H17),我们在日志中得到 TIMESTAMP'2015-09-13 10:17:17.602000'。错误的结果……似乎改变会话时区完全没有任何影响(我试过+14、-14……没有改变)。然而,SET 命令被正确执行 - 它出现在 SQL 日志中,并且 TIMEZONE() 的值随后发生变化。

其他尝试

我也尝试过使用 TIMESTAMP WITH TIME ZONE 列,但没有设置会话 TZ。在那种情况下,数据库存储 'local time +2',我可以从中提取正确的时间戳。这太荒谬了——这意味着 HSQLDB 驱动程序采用 Java 时间戳 (UTC),将其正确解释为 UTC,将其转换为 JVM 默认 TZ,然后将其发送到 DB。我不想要数据库中的 TZ 信息——不需要它。 (注意:更改会话 TZ 没有影响 - SQL 发出的命令始终与我的本地 TZ 一起...让您想知道 SET TZ 命令的意义何在)

将默认的 JVM TZ 更改为 UTC 是可行的,但如上所述我不能这样做。

另请注意:this question 似乎相关,但提供的答案基本上是破解我想避免的每个 SQL 订单...

我的问题

如何简单地将我的 UTC Java 时间戳存储在 HSQLDB 中? SET TIME ZONE 命令的目的是什么?

感谢阅读。

您的第一次尝试是正确的,return 将得到正确的结果。

您的数据库位于 UTC+2 时区。您正在连接,就好像您是 UTC 时区的远程用户一样。

时间戳的日志存储没有你说的错误。日志存储不是供数据库的用户读取的。数据库将其日志存储在您所在位置的时区中。下次它读取日志时,它会根据您的数据库时区读取并解释它(与会话时区无关)。因此,在日志中存储为 10:17 的时间将是 UTC 中的 8:17。

使用 TIMESTAMP WITHOUT TIME ZONE,数据库文件无法移动到不同的时区,因为时间戳将根据新位置的时区进行解释。

SET TIME ZONE语句的作用是允许在存储数据时进行正确的调整。它不会更改以前存储的数据。当然,如果时间存储为 8:17,无论何时何地在访问它时都应将其读取为 8:17。

为了获得最佳的可移植性,请使用 TIMESTAMP WITH TIME ZONE。即使您移动数据库文件,它存储和检索数据的方式也是正确的。