使用 java.util.Date 查询带有 TIMESTAMPTZ 的列

Use java.util.Date to query column with TIMESTAMPTZ

我对将 PostgreSQL 的 TIMESTAMPTZ 类型与官方 JDBC 驱动程序一起使用感到困惑。

如果我错了请纠正我,但是 PostgreSQL 和 Java 存储 TIMESTAMTZ 和 java.util.Date 相同:作为从 Unix 开始的毫秒数,定义为 1970-01-01 00:00:00 协调世界时。

因此,从技术上讲,我们正在对相同的 Long 值进行操作,我们应该不会有任何问题。

但是,我们遇到了很多问题,代码在一个或另一个方向上进行了大量转换,这些转换被更复杂的转换所取代,这些转换恰好在之后起作用。最终结果有点类似于 ,在两个方向上都转换为 UTC。在 Windows 下开发,更改时区被阻止,使得调试变得不容易。

如果我有一个 PostgreSQL table 列:

last_modified TIMESTAMP WITH TIMEZONE

我想用 Date 实例查询它:

Date modifiedAfter = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss").parse("2021-06-11 15:20:00");
PreparedStatement ps = conn.prepareStatement("Select * from mytable where last_modified > ?");
ps.setDate(1, modifiedAfter);

它将正常工作,因为 PostgreSQL JDBC driver 会将 java 日期转换为 UTC Long,使用我的 java 程序的区域设置,并且数据库服务器将使用它自己的区域设置何时会被查询?

或者如果服务器的区域设置与客户端的区域设置不同,则这些转换无法正确处理,因此我只需要在 UTC 日期上进行操作?

我对上面链接的答案的问题是,OP 声称它 'works for him',这意味着 Java 总是读取所写的内容,但不一定,该值正确存储在数据库中,以便其他客户端读取预期的内容。

上面的方法是处理 TIMESTAMTZ 的正确方法,以确保 both Java 代码和 PSQL 控制台中查询的输出将给出一致的结果?如果不是,正确的解决方案是什么?

我预计,当我用我的 Java 程序编写 '2021-11-06 15:00:00' 时 运行 TimeZone +4:

不要使用java.util.Date,使用java.time.OffsetDateTime

OffsetDateTime modifiedAfter = OffsetDateTime.of(2021, 6, 11, 15, 20, 0, 0, ZoneOffset.UTC);
ps.setObject(1, modifiedAfter);

读取值时做同样的事情:

ResultSet rs = statement.executeQuery(...);
while (rs.next()) {
  OffsetDateTime odt = rs.getObject(1, OffsetDateTime.class);
  ....
}

如果您根本不关心时区,并且确定所有内容总是指定相同的时区(例如 UTC),那么在 Postgres 中使用 timezone 作为列数据类型.

然后在Java

中使用LocalDateTime代替OffsetDateTime