为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

胡说叔叔 2023-07-13 15:33:47
我有一个简单的 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这是单元测试:@Testpublic 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:002019-05-30T11:54:32Z有趣的是,如果我在中部添加日期,小时会正确更改为山区,但往返后的输出仍然只是愉快地报告 Z。我认为这不是预期的?难道我做错了什么?如果没有,有什么可以在全球范围内应用的解决方法的想法吗?有几个开发人员对此感兴趣,我对每次选择时都必须使用一些特殊逻辑处理日期感到不兴奋,这似乎很脆弱。我一直在运行 3.10,但刚刚升级到 3.12,结果相同。
查看完整描述

2 回答

?
蛊毒传说

TA贡献1895条经验 获得超3个赞

这不是 jOOQ 问题。PostgreSQL 没有与ZonedDateTime. 它的TIMESTAMPTZorTIMESTAMP WITH TIME ZONE类型实际上只是一个java.time.Instant

对于带时区的时间戳,内部存储的值始终采用 UTC(通用协调时间,传统上称为格林威治标准时间,GMT)。指定了显式时区的输入值将使用该时区的适当偏移量转换为 UTC。如果输入字符串中未指定时区,则假定其处于系统 TimeZone 参数指示的时区,并使用时区的偏移量将其转换为 UTC。

jOOQ 无法为您做任何事。

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

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


查看完整回答
反对 回复 2023-07-13
?
BIG阳

TA贡献1859条经验 获得超6个赞

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

万一其他人也在运行这个 jar 组合,如果 impossibl 驱动程序中的功能是必要的,建议更新到 pgjdbc 0.8.2,如果不需要,则放弃。


查看完整回答
反对 回复 2023-07-13
  • 2 回答
  • 0 关注
  • 117 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信