给出此表:
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
为什么会发生这种转换,如何禁用它?
答案 0 :(得分:0)
无法禁用转换,因为PostgreSQL服务器会剥离时区信息并将时间戳始终存储在UTC中,即使您显式使用TIMESTAMP WITH TIME ZONE
类型也是如此。
对于带有时区的时间戳,内部存储的值始终为 UTC (通用协调时间,通常称为格林威治标准时间,格林尼治标准时间)。使用该时区的适当偏移量,将指定了明确时区的输入值转换为UTC。如果在输入字符串中未指定时区,则假定该时区位于系统的TimeZone参数指示的时区中,并使用时区时区的偏移量转换为UTC。
此外,文档指出:
我们不建议使用带时区的时间类型(尽管PostgreSQL支持遗留应用程序并符合SQL标准)。 PostgreSQL假定您的本地时区为仅包含日期或时间的任何类型。
问题中描述的怪异行为是因为
psql
控制台客户端在显示时间戳之前将时间戳转换为用户的本地时区,在这种情况下为德国时间(+02:00)感谢@RobbyCornelissen的见解。