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

标签 java jooq

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

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

通过在 jOOQ 中执行的语句将数据库强制到不同的时区似乎无济于事。

context.execute( "set timezone TO 'GMT';" ); // this has no effect

强制我的系统时间为 UTC 有效地解决了这个问题,但由于许多原因是 Not Acceptable 。

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

有趣的是,如果我在中部添加日期,小时会正确更改为山区,但往返后的输出仍然只是愉快地报告 Z。

我假设这不是预期的?难道我做错了什么?如果没有,是否有任何适用于全局的解决方法的想法?有几个开发人员对此感到兴奋,每次我们选择时都必须用一些特殊的逻辑来处理日期,这似乎很脆弱。

我一直在运行 3.10,但刚刚升级到 3.12,结果相同。

最佳答案

这不是 jOOQ 问题。 PostgreSQL 没有对应于 ZonedDateTime 的数据类型。它的 TIMESTAMPTZTIMESTAMP WITH TIME ZONE 类型实际上只是一个 java.time.Instant。考虑手册: https://www.postgresql.org/docs/current/datatype-datetime.html

For timestamp with time zone, the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone. If no time zone is stated in the input string, then it is assumed to be in the time zone indicated by the system's TimeZone parameter, and is converted to UTC using the offset for the timezone zone.

jOOQ 无能为力。

请注意,jOOQ 默认将所有 SQL 数据库中的 TIMESTAMP WITH TIME ZONE 类型映射到 java.time.OffsetDateTime,因为 JDBC 规范就是这样做的。对于像 JDBC(和 jOOQ)这样的供应商不可知的 API,这是一个合理的默认值。但是如果你想拥有 PostgreSQL 原生行为,我建议将所有 TIMESTAMPTZ 类型重写为 INSTANT(如果你使用的是 jOOQ 3.12+)。

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

关于java - jOOQ 将偏移日期时间返回为 Z(UTC),即使它不是,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57793193/

相关文章:

java - 限制和偏移的jooq问题

java - JOOQ从表中获取记录并将其插入到另一个表中

java - 如何用前导空格解析 LocalDateTime?

java - 为什么 Windows LookAndFeel 使字体太小?

java - JShell 中除了 java.lang 包之外还有哪些包会自动导入?

java - MapStruct 需要 Impl 类

java - 克隆 jOOQ Record 对象的推荐方法是什么?