简体   繁体   English

postgresql JDBC驱动程序使用客户端时区

[英]postgresql JDBC driver uses client time zone

I am using postgresql-42.2.2.jar jdbc driver and postgresql 9.6 server. 我正在使用postgresql-42.2.2.jar jdbc驱动程序和postgresql 9.6服务器。

How can I configure the connection to use server timezone instead of client timezone? 如何配置连接以使用服务器时区而不是客户端时区?

Query: 查询:

select id, TO_TIMESTAMP(tbl.ended_time / 1000)
FROM tbl
where TO_TIMESTAMP(tbl.ended_time / 1000) >= now()::date + interval '1m'

Running a query with pgadmin I am getting the following result (which is correct) 使用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"

but running the same query with JDBC driver the result is : 但是使用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

without where the running query with pgadmin the result is: 如果没有使用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"

Here is the code: 这是代码:

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();
    } 

}

As explained here , the JDBC driver uses your local time zone and not the server time zone. 正如解释这里的JDBC驱动程序使用本地时区而不是服务器时区。

Unfortunately there is no easy way to change that behaviour or to query the server's time zone. 不幸的是,没有简单的方法可以更改该行为或查询服务器的时区。

Also note that retrieving the data using an OffsetDateTime doesn't help much: 另请注意,使用OffsetDateTime检索数据并没有太大帮助:

rs.getObject(2, OffsetDateTime.class)

because unfortunately, the driver returns all OffsetDateTime s with an offset of 0 , so the timezone information is lost. 因为不幸的是,驱动程序返回了所有偏移量为0的 OffsetDateTime ,所以时区信息丢失了。

So it seems that your best bet is probably to either hardcode the database's timezone and calculate your time limit in Java or to store the timezone separately in your DB and query it. 因此,最好的选择似乎是对数据库的时区进行硬编码并使用Java计算时限,或者将时区分别存储在数据库中并进行查询。

TL;DR: it has nothing to do with JDBC driver. TL; DR:与JDBC驱动程序无关。 The SQL is flawed. SQL有缺陷。

What do you expect when comparing timestamp WITH time zone and timestamp withOUT time zone ? 比较timestamp WITH time zone timestamp withOUT time zone timestamp WITH time zone timestamp withOUT time zone timestamp WITH time zone您会有什么期望? Your SQL is just plain wrong, and thus it produces weird results. 您的SQL完全是错误的,因此会产生奇怪的结果。

What do you expect out of now()::date ? 您对now()::date有何期待? Note: PostgreSQL documentation does NOT state which timezone now() would produce. 注意:PostgreSQL文档没有说明now()将产生哪个时区。 It specifies just that "timezone will be there", however it could even change from one PG version to another one. 它仅指定“时区将存在”,但是它甚至可以从一个PG版本更改为另一个PG版本。 So you are basically requesting "a random value". 因此,您基本上是在要求“随机值”。

Please clarify what do you want to achieve, then write an appropriate SQL. 请阐明您要实现的目标,然后编写适当的SQL。 For instance, if you want to get records with timestamps "after 00:04:00 of the current day in a Europe/Berlin time zone", then you'd use something like 例如,如果要获取带有时间戳的记录“欧洲/柏林时区的当前日期的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'

The thing is there's no "start of a day" unless you specify which time zone you mean. 关键是没有“一天的开始”,除非您指定要表示的时区。 pgjdbc populates session with default timezone ( TimeZone.getDefault() ), so it is used in implicit conversions, however I would strongly advice you from comparing with and without timezone kind of datatypes in SQL no matter what you use to execute. pgjdbc填充使用默认时区的会话( TimeZone.getDefault()因此被隐式转换使用,但是我强烈对比,从建议你withwithout时区同类SQL数据类型的,不管你用什么来执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM