提问人:Oh hi Mark 提问时间:9/28/2023 最后编辑:AnonymousOh hi Mark 更新时间:9/28/2023 访问量:101
在 UTC 的 Postgres 中存储 ZonedDateTime
Storing ZonedDateTime in Postgres in UTC
问:
我收到一个 UTC 中的变量,我想在 UTC 中保留 Postgres 列。该列当前是 type of,我想阅读的格式相同。两者之间没有转换。ZonedDateTime
timestamptz
ZonedDateTime
回读它会转换为我不想要的本地时区。我的问题是,这是正确的吗?ZonedDateTime
timestamptz
答:
TL的;博士
写作:
myPreparedStatement.setObject( … , myZonedDateTime.toOffsetDateTime() )
检索:
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class )
您无法取回对象,因为在 Postgres 和 SQL 标准中都不支持将具有时区的时刻作为数据类型。ZonedDateTime
详
SQL 标准
SQL 标准几乎没有提及某些日期时间类型,而没有对细节和行为进行太多定义。因此,数据库在处理日期时间的方法上有很大差异。
SQL 标准定义了类型和 。但这些都是用词不当,是标准。作者的意思是与UTC的偏移量,而不是实际的时区。TIMESTAMP WITH TIME ZONE
TIMESTAMP WITHOUT TIME ZONE
JDBC 映射
因此,JDBC 标准将值映射到 java.time.OffsetDateTime
类型。该类型表示与UTC偏移量为一定小时-分钟-秒的时刻,正(向东)或负(向西)。TIMESTAMP WITH TIME ZONE
JDBC 既不寻址 java.time.ZonedDateTime
类,也不寻址。java.time.Instant
转换为ZonedDateTime
OffsetDateTime
我在 UTC 中收到一个变量作为 ZonedDateTime,我想在 UTC 中保留 Postgres 列。
将 ur 转换为 .ZonedDateTime
OffsetDateTime
OffsetDateTime odt = myZdt.toOffsetDateTime() ;
例如,今年分配了区域的日期时间将转换为偏移量为 或 的日期时间。Europe/Paris
+01:00
+02:00
在数据库中写入/检索
对象中的特定偏移量无关紧要。当保存到 类型的 Postgres 列时,任何提供的偏移量或区域信息都用于将值调整为零小时-分钟-秒的偏移量。此调整是特定于 Postgres 的行为,未在标准中指定。其他一些数据库也这样做,有些则不然。OffsetDateTime
TIMESTAMP WITH TIME ZONE
发送到数据库。
myPreparedStatement.setObject( … , odt ) ;
检索。
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
您无法直接取回您的对象。如上所述,Postgres 和 SQL 标准都没有使用时区存储日期时间。ZonedDateTime
如果原始时区对您很重要,则必须将其单独存储在另一个文本列中。
myPreparedStatement.setString( … , zdt.getZone().toString() ) ;
检索。
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
ZoneId zoneId = ZoneId.of( myResultSet.getString( … ) ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( zoneId ) ;
顺便说一句,请注意,时区名称有时会发生变化。
始终 UTC
Postgres 始终将日期时间值存储在偏移量为零的列中。TIMESTAMP WITH TIME ZONE
JDBC 始终从列中检索值作为偏移量为零的对象。TIMESTAMP WITH TIME ZONE
OffsetDateTime
⚠️ 不幸的是,一些工具、中间件和框架选择注入默认时区或偏移量。在数据库和您之间,检索到的 UTC 值可能会被调整。这不会发生在直接 JDBC 上。但要注意建立在JDBC之上的框架;这些可以选择注入偏移量或区域。虽然用心良苦,但这种反功能确实会引起很多混乱。
使用完整类型名称
我建议你不要使用缩写.timestampz
首先,该术语是 Postgres 专有的,而不是标准的。
另一方面,这个词太容易被误读为.鉴于正确选择 versus 的重要性,我建议始终将它们拼出来。timestamp
TIMESTAMP WITH TIME ZONE
TIMESTAMP WITHOUT TIME ZONE
评论
timestamptz
不存储时区或偏移量。它只是将值存储为 UTC 时间。读取日期时间:第 8.5.1.3 节。完整说明的时间戳。java.time
ZonedDateTime
对于 UTC 中的日期和时间来说,它并不是正确的类型。如果可以更改它,请选择更正确且重量更轻。OffsetDateTime