使用java.util.Date查询TIMESTAMPTZ列



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

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

因此,从技术上讲,我们是在相同的长期价值上操作的,我们应该不会出现任何问题。

然而,我们在代码向一个或另一个方向进行大量转换时遇到了很多问题,这些转换被更复杂的转换所取代,而这些转换恰好在之后工作。最终结果与https://stackoverflow.com/a/6627999/5479362,双向转换为UTC。在Windows下进行开发,因为更改时区被阻止,所以调试起来并不容易。

如果我有一个PostgreSQL表,其中列为:

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驱动程序将使用我的java程序的Locale将java日期转换为UTC Long,而DB服务器将在查询该日期时使用自己的Locale?

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

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

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

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

  • TimeZone+2的Java程序将获得"2021-11-06 13:00:00">
  • 时区为+1的PSQL客户端将获得"2021-11-06 12:00:00">
  • 实习生,时间是"2021-11-06 11:00:00">

不要使用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

最新更新