【发布时间】:2020-11-12 17:26:36
【问题描述】:
我写了一个带有两个 Instant 字段的简单 Java 实体:
@Entity
@Table(name = "tb_foo")
public class Foo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(columnDefinition = "TIMESTAMP WITHOUT TIME ZONE")
private Instant date1;
@Column(columnDefinition = "TIMESTAMP WITHOUT TIME ZONE")
private Instant date2;
...
然后我在项目的资源根文件夹中写了一个简单的 import.sql 来测试 UTC/Local 是否工作:
INSERT INTO tb_foo (date1, date2) VALUES ('2020-07-22T20:50:01.12345Z', NOW());
由于我的本地时区是 GMT-3,因此上面的 20:50:01 应该在客户端显示为 17:50:01,并且 NOW() 应该显示为与我的本地时间相同(大约 0:25 在我测试的那一刻)。我在 H2 数据库中对其进行了测试,它运行良好:
这是由 JPA 自动生成到 H2 的 DDL 和 INSERT:
create table tb_foo (
id bigint generated by default as identity,
date1 TIMESTAMP WITHOUT TIME ZONE,
date2 TIMESTAMP WITHOUT TIME ZONE,
primary key (id)
)
INSERT INTO tb_foo (date1, date2) VALUES ('2020-07-22T20:50:01.12345Z', NOW())
但是,当我在 Postgres (12.x) 上测试相同的 Java 和 SQL 代码时,它不起作用(20h UTC 显示为 20 而不是 17):
这是 JPA 自动生成到 Postgresql 的 DDL 和 INSERT:
create table tb_foo (
id int8 generated by default as identity,
date1 TIMESTAMP WITHOUT TIME ZONE,
date2 TIMESTAMP WITHOUT TIME ZONE,
primary key (id)
)
INSERT INTO tb_foo (date1, date2) VALUES ('2020-07-22T20:50:01.12345Z', NOW())
我错过了什么?
更新:
我又做了一个测试:我通过 Java 写了另一个数据库插入(不是 SQL INSERT):
Foo foo = new Foo(null, Instant.parse("2020-07-23T20:50:01Z"), Instant.now());
fooRepository.save(foo);
这次 UTC 时间戳 20:50 被正确插入到 Postgresql 中!它在 pgadmin 客户端上显示为 17:50!所以也许正确的问题是:
如何在 SQL INSERT 调用中为 Postgresql 正确指定文字 UTC 时间戳以将其存储在没有时区的时间戳中?
我尝试了两种方式:
INSERT INTO tb_foo (date1, date2) VALUES ('2020-07-22T20:50:01.12345Z', NOW());
INSERT INTO tb_foo (date1, date2) VALUES ('2020-07-22 20:50:01 +00', NOW());
两者都不起作用(在 GMT-03 系统的 pgadmin 客户端上,它们都显示 20:50 而不是 17:50)。
【问题讨论】:
-
分享 H2 & Postgres 中使用的 DDL
-
@PrasadU 你去。我已经编辑了问题。
-
您将
2020-07-22T20:50:01.12345Z存储到定义为timestamp WITHOUT time zone的列中,因此该值“按原样”获取并“按原样”返回。听起来好像你真的想要 Postgres 中的timestamp WITH time zone -
@a_horse_with_no_name 我认为这不是重点。为了澄清我已经测试了 NOW() 时间戳。由于 pgadmin 客户端将 NOW() 时间戳显示为我的本地时间 (GTM-3),因此 UTC 文字 20:50 应该显示为 17:50,就像 H2 客户端一样。 NOW() 时间戳是一种测试数据库客户端是否向用户显示没有时区的时间戳作为本地或 UTC(在这两种情况下都是本地的)的方法。
-
没有什么真正迫使客户端(在这种情况下我假设 pgadmin)将存储的时间调整到您的区域。我认为 postgres 客户端通过不做任何事情来向您展示正确的价值。在向最终用户提供数据时,由您的后端或 Web 客户端进行最终的显示调整。
标签: java postgresql jpa