PostgreSQL 9.2 JDBC驱动程序使用客户端时区吗?

23

在使用PostgreSQL JDBC驱动连接PostgreSQL数据库时,我遇到了一个有趣的挑战。最新版本的驱动程序9.2在执行日期/时间匹配时似乎使用客户端时区。

当服务器(JasperReports Server)设置为UTC而数据库服务器设置为US/Eastern时,就会出现问题。

如果我在一个设置为UTC时区的客户端上运行以下查询,则使用9.0 JDBC驱动程序和9.2 JDBC驱动程序会得到不同的结果。

select now(), extract(timezone FROM now()), current_setting('TIMEZONE'), now()-interval '1 hour' as "1HourAgo"

使用9.0 JDBC驱动程序的结果:

now                         date_part   current_setting     1HourAgo
2013-08-26 15:33:57.590089  -14,400     US/Eastern          2013-08-26 14:33:57.590089

使用9.2 JDBC驱动程序的结果:

now                         date_part   current_setting     1HourAgo
2013-08-26 15:41:49.067903  0           UTC                 2013-08-26 14:41:49.067903

这会导致查询语句中的WHERE子句返回不正确的结果。例如,

WHERE end_time between now() - interval '1 hour' and now()

使用9.0驱动程序时可以正常工作,但使用9.2驱动程序却没有结果,因为驱动程序似乎会偏移end_time的值以匹配UTC(客户端的时区)。以下是一个丑陋的解决方法:

WHERE end_time at time zone 'EDT' between now() - interval '1 hour' and now()

问题:

  1. 有其他人遇到过这种情况吗?
  2. 这种行为变化有解释吗?我在JDBC发行说明中找不到任何信息。
  3. 除了将驱动程序回滚到旧版本之外,是否有关于如何解决此问题的建议?

谢谢!

5个回答

16

我自己也遇到了这个问题。 我确认Postgres JDBC驱动程序确实从JVM中获取连接时区,并且我找不到覆盖此行为的方法。 如果他们提供了一个JDBC URL连接参数,那就太好了。

作为解决方法,我发现我的连接池库(HikariCP)可以为每个新连接执行SQL语句:

hikariConfig.setConnectionInitSql("set time zone 'UTC'");

7
JVM使用操作系统报告的时区 - 如果不正确,应更改操作系统设置。但是,在启动JVM时,您可以通过指定“-Duser.timezone = UTC”来覆盖此设置。 - user330315
5
可以,但并不总是希望使用与 jvm 相同的时区。 - JimN
我通过进入我的“/opt/sqldeveloper/ide/bin/ide.conf”并添加“AddVMOption -Duser.timezone=UTC”来实现这一点。 - Mattiavelli
对我来说似乎没有任何影响 @JimN - deFreitas
@JimN的解决方案也可以使用C3P0实现。您需要实现com.mchange.v2.c3p0.ConnectionCustomizer接口(onAcquire方法),并设置c3p0.connectionCustomizerClassName配置属性。 - Emmanuel Guiton

5

谢谢你的回答,马克。然而,它并没有真正回答我的问题,我的问题是关于 PostgreSQL JDBC 驱动在9.0和9.2之间的更改。9.2 似乎正在使用客户端时区,而不是驱动程序所在的服务器时区,而 9.0 则没有这种情况。这是驱动程序工作方式的严重变化,无论标准应该是什么。 - JTShyman
我大致浏览了JDBC驱动程序的发行说明,但没有看到任何表明变化的内容。我建议你在pgsql-jdbc邮件列表上询问。 - Mark Rotteveel
以防万一:此提交在连接阶段添加了TimeZone会话参数,这使得数据库在无法确定数据所在时区的计算中使用客户端时区。 - Vladimir Sitnikov

4

简短版本尝试:

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

您好,我们遇到了客户端和服务器时区不匹配的问题。我们需要使用“UTC”运行我们的单元测试。通过查看Postgres JDBC驱动程序的源代码(这是测试代码),我们在获取连接之前更改了JVM中的TZ来“修复”它。


你把这行代码放在哪里了? - undefined

2

如果其他人也遇到了这个问题 - 你可以编辑启动SQLDeveloper的"conf"文件并添加以下行:

AddVMOption -Duser.timezone=UTC

我在我的电脑上找到了这个文件:

/opt/sqldeveloper/ide/bin/ide.conf

感谢@a_horse_with_no_name在其他答案的评论中指出正确方向


0

我不熟悉JasperReports,但一般来说,使用JSR-310(Java 8)日期/时间类型(由JDBC 4.2支持)应该可以正常工作,无需担心数据库服务器和客户端之间的时区不匹配问题。

请参阅PostgreSQL JDBC驱动程序文档中的使用Java 8日期和时间类


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接