【问题标题】:Use java.util.Date to query column with TIMESTAMPTZ使用 java.util.Date 查询带有 TIMESTAMPTZ 的列
【发布时间】:2021-06-11 13:31:59
【问题描述】:

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

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

因此,从技术上讲,我们使用相同的 Long 值进行操作,我们应该不会遇到任何问题。

但是,我们在代码在一个或另一个方向上进行大量转换时遇到了很多问题,这些转换被更复杂的转换所取代,而这些转换恰好在之后起作用。最终结果有点类似于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 driver 将使用我的 java 程序的语言环境将 java 日期转换为 UTC Long,并且当查询该日期时数据库服务器将使用它自己的语言环境?

或者如果服务器的语言环境与客户端的语言环境不同,那么这些转换没有正确处理,因此我只需要在 UTC 日期进行操作?

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

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

我希望,当我使用运行 TimeZone +4 的 Java 程序编写“2021-11-06 15:00:00”时:

  • 带有 TimeZone +2 的 Java 程序将获得 '2021-11-06 13:00:00'
  • 带有 TimeZone +1 的 PSQL 客户端将获得“2021-11-06 12:00:00”
  • 实习生,会是'2021-11-06 11:00:00'

【问题讨论】:

  • Sun、Oracle 和 JCP 社区在一致采用定义 java 的 JSR 310 时放弃了可怕的 Date、Calendar、Timestamp 和 SimpleDateFormat 类.time 类。我建议你也转到 java.time。

标签: java postgresql timezone timestamp-with-timezone


【解决方案1】:

不要使用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)指定,那么请使用 timezone 作为 Postgres 中的列数据类型。

然后在 Java 中使用 LocalDateTime 而不是 OffsetDateTime

【讨论】:

  • 是否需要使用 ZoneOffset.UTC 才能让 JDBC 驱动程序按预期工作?我刚刚意识到我缺乏对实际发送到数据库的内容的理解
  • 发送到数据库的值将被调整为当前连接指定的时区(show timezone;会告诉你它是哪一个)并由驱动程序初始化为客户端计算机的时区
  • 在这种情况下,java.util.Date 不应该同样工作吗?因为从技术上讲,java.util.Date 是表示自 A.U. 以来毫秒数的 long 的包装器。在UTC。理论上,没有什么可以转换的。我认为我所有的问题都来自于对字里行间发生的事情缺乏了解:stackoverflow.com/questions/67938171/…
  • 不,java.util.Date 完全没有时区的概念。 java.util.Date 和相应的 java.sql.Timestamp 和 java.sql.Date 类应视为已弃用。停止使用它们。
  • 是的,但 java.util.Date 在这方面与 timestamptz 没有区别。表达式“选择'2021-06-11 14:00+02'::timestamptz = '2021-06-11 16:00+04'::timestamptz;”返回“真”。因此,我很惊讶这种类型会产生问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-05
  • 1970-01-01
  • 2013-09-25
  • 1970-01-01
  • 2011-07-06
相关资源
最近更新 更多