给定此表:
CREATE TABLE a(
t TIMESTAMP WITH TIME ZONE
);
这个简单的JDBC代码片段:
DriverManager.getConnection(
"jdbc:postgresql://localhost:5432/dbname", "user", "password"
).use { connection ->
val nowSomeTimeZone = OffsetDateTime.now(ZoneOffset.of("+4"))
connection.prepareStatement("insert into a(t) values (?)").use { insertStmt ->
insertStmt.setObject(1, nowSomeTimeZone)
insertStmt.executeUpdate()
}
connection.createStatement().use { stmt ->
stmt.executeQuery("select * from a").use { resultSet ->
resultSet.next()
val t = resultSet.getObject(1, OffsetDateTime::class.java)
println("$nowSomeTimeZone -> $t")
}
}
}
必须在JDBC堆栈内的某个位置发生从+04:00到UTC的自动转换,因为这是
println
输出:2018-08-30T10:35:33.594+04:00 -> 2018-08-30T06:35:33.594Z
更奇怪的是,当我使用
psql
控制台客户端查看表格时,它向我显示了另一个时区(这是我的本地时区)中的时间戳:$ psql -h localhost -U username
dbname=> select * from a;
t
----------------------------
2018-08-30 08:35:33.594+02
为什么会发生这种转换,如何禁用它?
最佳答案
禁用转换是不可能的,因为PostgreSQL服务器会剥离时区信息并将时间戳始终存储在UTC中,即使您明确使用TIMESTAMP WITH TIME ZONE
类型也是如此。
引用PostgreSQL documentation:
对于带有时区的时间戳,内部存储的值始终以UTC(通用协调时间,传统上称为格林威治标准时间,GMT)表示。使用该时区的适当偏移量,将指定了明确时区的输入值转换为UTC。如果在输入字符串中未指定时区,则假定该时区位于系统的TimeZone参数指示的时区中,并使用时区时区的偏移量转换为UTC。
此外,文档指出:
我们不建议使用带时区的时间类型(尽管PostgreSQL支持遗留应用程序并符合SQL标准)。 PostgreSQL假定您的本地时区为仅包含日期或时间的任何类型。
问题中描述的怪异行为是因为
JDBC驱动程序始终以UTC返回时间戳记psql
控制台客户端在显示时间戳之前将时间戳转换为用户的本地时区,在这种情况下为德国时间(+02:00)
感谢@RobbyCornelissen的见解。
关于java - 在PostgreSQL中存储OffsetDateTime时如何禁用到UTC的转换,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52092746/