【问题标题】:PostgreSQL 9.2 JDBC driver uses client time zone?PostgreSQL 9.2 JDBC 驱动程序使用客户端时区?
【发布时间】:2013-08-29 04:06:22
【问题描述】:

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

当服务器(JasperReports 服务器)设置为 UTC 并且数据库服务器设置为美国/东部时,这会成为一个问题。

如果我从设置为 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. 除了将驱动程序回滚到旧版本之外,关于如何解决此问题的任何建议?

谢谢!

【问题讨论】:

    标签: postgresql jdbc timezone


    【解决方案1】:

    JDBC 标准(和 API 文档)要求使用本地时区作为默认时区,并由 PreparedStatement.setTimestamp 明确说明。但是,它也适用于 JDBC 设置或检索时间相关数据的所有其他领域。

    另见我对Is java.sql.Timestamp timezone specific?的回复

    【讨论】:

    • 感谢您的回答,马克。但是,它并没有真正回答我的问题,该问题特定于 PostgreSQL 的 JDBC 驱动程序在 9.0 和 9.2 之间的变化。 9.2 似乎选择了 client 时区,而不是驱动程序所在的 server 时区,而 9.0 则没有。无论标准应该是什么,这都是驱动程序工作方式的重大变化。
    • 我浏览了 JDBC 驱动程序的发行说明,但没有看到任何表明更改的内容。我建议你在 pgsql-jdbc 邮件列表上询问。
    【解决方案2】:

    我自己也遇到了这个问题。我验证了 postgres jdbc 驱动程序确实从 jvm 获取连接时区,但我无法找到覆盖此行为的方法。如果他们为此提供了一个 jdbc url 连接参数,那就太好了。

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

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

    【讨论】:

    • JVM 使用操作系统报告的时区 - 如果这不正确,您可能应该更改操作系统设置。但是您可以通过在启动 JVM 时指定 -Duser.timezone=UTC 来覆盖它
    • 当然可以,但您并不总是希望使用与 jvm 相同的时区。
    • 我可以通过进入我的“/opt/sqldeveloper/ide/bin/ide.conf”并添加“AddVMOption -Duser.timezone=UTC”来做到这一点
    • 它似乎对我没有影响@JimN
    • @JimN 的解决方案也可以使用 C3P0 实现。您需要实现com.mchange.v2.c3p0.ConnectionCustomizer接口(@98​​7654324@方法)并设置c3p0.connectionCustomizerClassName配置属性。
    【解决方案3】:

    以防万一其他人对此感到困惑 - 您可以编辑启动 SQLDeveloper 的“conf”文件并添加以下行:

    AddVMOption -Duser.timezone=UTC
    

    我在我的机器上找到了这个文件:

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

    感谢@a_horse_with_no_name 在其他答案之一中发表评论指出我正确的方向

    【讨论】:

      【解决方案4】:

      我不知道 JasperReports,但一般来说,使用 JSR-310 (Java 8) 日期/时间类型(受 JDBC 4.2 支持)应该可以工作,而不必担心数据库服务器和客户端之间的时区不匹配。

      请参阅 PostgreSQL JDBC 驱动程序文档中的 Using Java 8 Date and Time classes

      【讨论】:

        【解决方案5】:

        短版试试:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-10-27
          • 1970-01-01
          • 2018-03-28
          • 2013-10-25
          • 2012-12-01
          • 1970-01-01
          • 2011-04-20
          相关资源
          最近更新 更多