JDBC插入now()与服务器时间戳不同

时间:2014-10-02 14:22:54

标签: java postgresql jdbc timezone timestamp

对于这个PostgreSQL测试表:

CREATE TABLE public.test (
  id BIGSERIAL,
  "datetime" TIMESTAMP WITHOUT TIME ZONE DEFAULT now(),
  value INTEGER,
  CONSTRAINT test_pkey PRIMARY KEY(id)
) 

我正在使用这个SQL插件:

INSERT INTO it.test (value) VALUES (1);

从EMS或PgAdmin等远程客户端执行INSERT时没问题。字段datetime完全填充了服务器时间戳,但是当我使用Postgres / JDBC Driver(postgresql-9.2-1002.jdbc4.jar)从Java程序执行INSERT时,字段datetime填充了与服务器不同的时间戳

我读到JVM使用本地PC时区。有什么方法可以避免这种情况吗?

如果我将数据类型从timestamp更改为timestampz,java会使用服务器时间戳填充该字段,但我想在不更改数据类型的情况下解决它,因为该表由其他程序和报告使用。

1 个答案:

答案 0 :(得分:2)

这里的问题是PgJDBC在连接时将TimeZone变量设置为JVM时区。它要求它的时间戳代码能够正确运行,并且(IIRC)要正确地遵守JDBC规范。 (有关详细信息,请参阅createPostgresTimeZone中的org/postgresql/core/v3/ConnectionFactoryImpl.java。)

now()current_timestamp的别名,返回timestamp with time zone

timestamp with time zonetimestamp without time zone的强制转换与撰写current_timestamp at time zone [the current server TimeZone]相同,即将时间戳重新解释为在新时区。

由于当您通过其他客户端连接时TimeZone不同,您会得到不同的结果。因此,对于将TimeZone设置为当地时间的客户,您的DDL也会出错。

要使其保持一致,请创建列timestamp with time zone(通常更可取),或将default重新定义为:

"datetime" TIMESTAMP WITHOUT TIME ZONE DEFAULT now() AT TIME ZONE 'CEST',

...或服务器时区。如果这样做,要小心!指定时区的方法有三种,必须确保使用与服务器配置相同的方法,否则会有不同的日光节省时间处理!

毋庸置疑,我强烈建议您使用UTC:

"datetime" TIMESTAMP WITHOUT TIME ZONE DEFAULT current_timestamp AT TIME ZONE 'UTC',

或最好是timestamp with time zone

"datetime" TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp,