我正在使用postgresql-42.2.2.jar jdbc驱动程序和postgresql 9.6服务器。
如何配置连接以使用服务器时区而不是客户端时区?
查询:
select id, TO_TIMESTAMP(tbl.ended_time / 1000)
FROM tbl
where TO_TIMESTAMP(tbl.ended_time / 1000) >= now()::date + interval '1m'
使用pgadmin运行查询我得到以下结果(正确)
"2185" "2018-06-22 00:02:02-05"
"2186" "2018-06-22 00:03:01-05"
"2187" "2018-06-22 00:13:02-05"
但是使用JDBC驱动程序运行相同的查询,结果是:
2169 2018-06-22 07:13:01.0
2181 2018-06-22 08:33:02.0
2180 2018-06-22 08:23:01.0
2185 2018-06-22 09:02:02.0
2186 2018-06-22 09:03:01.0
2187 2018-06-22 09:13:02.0
在没有使用pgadmin运行查询的情况下,结果是:
"2169" "2018-06-21 22:13:01-05"
"2181" "2018-06-21 23:33:02-05"
"2180" "2018-06-21 23:23:01-05"
"2185" "2018-06-22 00:02:02-05"
"2186" "2018-06-22 00:03:01-05"
"2187" "2018-06-22 00:13:02-05"
代码如下:
static String URL = "jdbc:postgresql://some_ip:7000/db";
static String USERNAME = "test";
static String PASSWORD = "test";
static String JDBC_DRIVER = "org.postgresql.Driver";
public static void main(String[] args) {
String query = "select id, TO_TIMESTAMP(tbl.ended_time / 1000) FROM tbl where TO_TIMESTAMP(tbl.ended_time / 1000) >= now()::date + interval '1m'";
Connection conn = null;
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(query);
while (rs.next()) {
System.out.println(rs.getObject(1) + "--" + rs.getObject(2));
}
rs.close();
st.close();
conn.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
答案 0 :(得分:0)
如here所述,JDBC驱动程序使用您的本地时区而不是服务器时区。
不幸的是,没有简单的方法来更改该行为或查询服务器的时区。
还请注意,使用OffsetDateTime
检索数据并没有太大帮助:
rs.getObject(2, OffsetDateTime.class)
不幸的是,驱动程序返回了所有OffsetDateTime
个with an offset of 0,因此时区信息丢失了。
因此,最好的选择似乎是对数据库的时区进行硬编码并用Java计算时限,或者将时区分别存储在数据库中并进行查询。
答案 1 :(得分:0)
TL; DR:与JDBC驱动程序无关。 SQL有缺陷。
比较timestamp WITH time zone
和timestamp withOUT time zone
会有什么期望?您的SQL完全是错误的,因此会产生奇怪的结果。
您对now()::date
有什么期待?注意:PostgreSQL文档没有说明将产生哪个时区now()
。它仅指定“时区将存在”,但是它甚至可以从一个PG版本更改为另一个PG版本。因此,您基本上是在要求“随机值”。
请阐明您要实现的目标,然后编写适当的SQL。 例如,如果您想获取带有时间戳的记录“在欧洲/柏林时区的当天的00:00:00之后”,那么您将使用类似的
where TO_TIMESTAMP(tbl.ended_time / 1000) >=
((now() at time zone 'Europe/Berlin')::date + interval '4m')::timestamp
at time zone 'Europe/Berlin'
问题是,除非您指定要表示的时区,否则就没有“一天的开始”。 pgjdbc
使用默认时区(TimeZone.getDefault()
)填充会话,因此它在隐式转换中使用,但是我强烈建议您比较一下with
和without
时区类型的数据类型,不管您使用什么执行SQL。