对于这个 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 驱动程序 (postgresql-9.2-1002.jdbc4.jar) 从 Java 程序执行 INSERT 时,字段 datetime 填充了与服务器不同的时间戳.
我读到 JVM 使用本地 PC 时区。有什么办法可以避免这种情况?
如果我将数据类型从 timestamp 更改为 timestampz,java 将使用服务器时间戳填充该字段,但我想在不更改数据类型的情况下解决它,因为该表已被其他程序和报告使用。
最佳答案
这里的问题是 PgJDBC 在连接时将 TimeZone
变量设置为 JVM 时区。它要求它的时间戳代码正确运行并且 (IIRC) 正确地遵守 JDBC 规范。 (有关详细信息,请参阅 org/postgresql/core/v3/ConnectionFactoryImpl.java
中的 createPostgresTimeZone
)。
now()
是 current_timestamp
的别名,它返回一个 timestamp with time zone
。
从 timestamp with time zone
到 timestamp without time zone
的转换与编写 current_timestamp at time zone [当前服务器 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',
或者最好是带有时区的时间戳
:
"datetime" TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp,
关于java - JDBC 插入与服务器时间戳不同的 now(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26162964/