Java jOOQ将偏移日期时间返回为Z(UTC),即使它不是

Java jOOQ将偏移日期时间返回为Z(UTC),即使它不是,java,jooq,pgjdbc-ng,Java,Jooq,Pgjdbc Ng,我有一个简单的Postgres测试表id,带有时区的时间戳。下面的测试和输出应该是自解释的,但总而言之,我插入了一行,该行的时间戳偏移量为-6。它被正确地插入到数据库中,然后以相同的时间从数据库中加载,但偏移量是错误的,特别是Z而不是-6 我尝试将数据库设置为UTC,当我在命令行手动选择时,它会正确地以UTC显示时间。将数据库设置为mountain,它以-6的偏移量显示预期时间 通过在jOOQ中执行的语句将数据库强制到不同的时区似乎没有任何作用 context.execute( "set tim

我有一个简单的Postgres测试表id,带有时区的时间戳。下面的测试和输出应该是自解释的,但总而言之,我插入了一行,该行的时间戳偏移量为-6。它被正确地插入到数据库中,然后以相同的时间从数据库中加载,但偏移量是错误的,特别是Z而不是-6

我尝试将数据库设置为UTC,当我在命令行手动选择时,它会正确地以UTC显示时间。将数据库设置为mountain,它以-6的偏移量显示预期时间

通过在jOOQ中执行的语句将数据库强制到不同的时区似乎没有任何作用

context.execute( "set timezone TO 'GMT';" ); // this has no effect
将我的系统时间强制为UTC有效地解决了这个问题,但由于许多原因,这是不可接受的

TimeZone.setDefault( TimeZone.getTimeZone( "UTC" ) ); // this is a band aid that works, but is not sustainable
下面是单元测试:

@Test
public void confirmDateRoundTripFromDb() throws SQLException, DatatypeConfigurationException
{
    ZonedDateTime testDate = ZonedDateTime.of( 2019, 05, 30, 12, 54, 32, 203, TimeUtilities.CENTRAL_ZONEID );

    final OffsetDateTime testDateAsOffset = testDate.toOffsetDateTime( );

    try( PGConnection dbConnection = DatabaseUtility.getPostgresConnection( _unitTestConfig.getSection("Postgres").getProperties(), _testDbName ) )
    {
        DSLContext context = DSL.using( dbConnection, SQLDialect.POSTGRES );
        DateTestsRecord dateTestsRecord = context.newRecord( DATE_TESTS );
        dateTestsRecord.setTestTimestamp( testDateAsOffset );
        dateTestsRecord.store();

        int id = dateTestsRecord.getId();

        DateTestsRecord insertedRecord = context.selectFrom( DATE_TESTS ).where( DATE_TESTS.ID.eq( id ) ).fetchAny();
        System.out.println( testDateAsOffset );
        System.out.println( insertedRecord.getTestTimestamp() );
    }
}
以及输出:

2019-05-30T12:54:32.000000203-05:00
2019-05-30T11:54:32Z
有趣的是,如果我在central中添加一个日期,小时将正确地更改为mountain,但是往返之后的输出仍然只是Z

我想这是意料之外的?我做错什么了吗?如果没有,有什么可以应用于全球的解决方案吗?在这方面有几个开发人员,我对每次我们选择时都要用一些特殊的逻辑来处理日期不感兴趣,这似乎很脆弱


我一直在运行3.10,但刚刚升级到3.12,结果也一样

这不是jOOQ的问题。PostgreSQL没有与ZoneDateTime对应的数据类型。它的TIMESTAMPTZ或timestampwithtimezone类型实际上只是一个java.TIME.Instant。考虑手册:

对于带有时区的时间戳,内部存储的值始终为UTC世界协调时间,传统上称为格林威治标准时间(GMT)。具有指定明确时区的输入值将使用该时区的适当偏移量转换为UTC。如果输入字符串中未说明时区,则假定它位于系统时区参数指示的时区中,并使用时区的偏移量转换为UTC

jOOQ在这里帮不了你什么

请注意,jOOQ默认将所有SQL数据库中带有时区类型的时间戳映射到java.TIME.OffsetDateTime,因为JDBC规范就是这样做的。对于像JDBC和jOOQ这样的与供应商无关的API来说,这是一个合理的默认值。但是如果您想拥有PostgreSQL本机行为,如果您使用的是jOOQ 3.12+,我建议将所有TIMESTAMPTZ类型重写为INSTANT


如果出于某种原因需要维护此信息,则需要将其存储在单独的列中,或文本列作为格式化值。

impossibl pgjdbc驱动程序版本0.7.1和jOOQ之间不兼容,导致在从postgres数据库中选择带时区的时间戳时不应用偏移量


如果其他人也在运行这种JAR组合,如果impossibl驱动程序中的功能是必需的,建议更新到pgjdbc 0.8.2,否则建议放弃

感谢您的回复,卢卡斯,非常感谢您在jOOQ周围回答问题。在我的问题中,我添加了一个更新来回应这个问题。太长,无法添加评论。@Evan:我可以建议您恢复编辑并提出新问题吗?对于这个问题的未来访问者来说,它可能不会那么让人困惑……很高兴做您认为最好的事情,我要提到的是,编辑是从原始问题中选择插入的数据,Java代码片段也是原始问题的单元测试代码的扩展。移动到@LukasEder@Evan:将在重新打开后立即进行调查,谢谢。我已经完全忘记了显示此问题的项目使用的是impossibl pgjdbc ng驱动程序,特别是版本0.7.1。我们的一个开发人员曾经使用过触发器,但后来放弃了。显然,这是这个问题的一个关键点。在尝试为此问题创建mvce时,我无法使用标准postgres驱动程序或impossibl 0.8.2驱动程序进行复制。不可能的0.7.1驱动程序似乎不适用于flyway。但是,将我们的项目从impossibl迁移出去可以解决这个问题,并且上面的测试通过了。我已经删除了链接的问题,没有必要让其中的两个问题四处游荡。Lukas,考虑到这个库现在有一个更新的版本,并且所讨论的版本不适用于mvce示例,我不会为此推送mvce。mvce项目是一个伟大的想法,如果我没有开始尝试从头开始复制,我就不会意识到库的差异存在。谢谢你的帮助。