Java 在使用jdbc时如何使用时区保存正确的日期时间

Java 在使用jdbc时如何使用时区保存正确的日期时间,java,postgresql,jdbc,timezone,Java,Postgresql,Jdbc,Timezone,我正在使用Java和JDBC连接到PostgreSQL数据库。我在将时间保存到数据库时遇到问题。我的数据库中有一个表student,其列如下所示 Id,Name,Created_at(timestamp) //some row here 我使用JDBC连接到PostgreSQL并保存数据 jdbc:postgresql://localhost:3306/someDatabase?useSSL=false&serverTimezone=UTC 当我插入数据时,我的数据看起来像 Stu

我正在使用Java和JDBC连接到PostgreSQL数据库。我在将时间保存到数据库时遇到问题。我的数据库中有一个表student,其列如下所示

Id,Name,Created_at(timestamp)

//some row here
我使用JDBC连接到PostgreSQL并保存数据

jdbc:postgresql://localhost:3306/someDatabase?useSSL=false&serverTimezone=UTC
当我插入数据时,我的数据看起来像

Student student = new Student()
student.name = "some name";
student.createdAt = LocalDateTime.now()
//一些逻辑保存

但是,当我插入数据库时,PostgreSQL保存的时间与我的服务器保存的时间相同。我想如果我的时间服务器是“2021-10-10 00:00:00”,当我保存到数据库时,它必须以 "2021-10-09 15:00:00". 我想当它保存它必须转换为时区日本

当我选择数据库时,PostgreSQL+9上的时区。如果我更改代码,例如:

TimeZone.setDefault(TimeZone.getTimeZone("UTC"))

这对我没有帮助。

您使用了错误的类和类型

切勿使用
时区
时间戳
类。这些是Java最早版本中糟糕的日期时间类的一部分,多年前被JSR310中定义的现代Java.time类所取代。特别被
ZoneId
Instant
/
OffsetDateTime
取代

在Postgres中,确保在列创建的
类型为带时区的
时间戳
,而不是不带时区的

通常最好将当前时刻捕捉为
瞬间
。该类表示UTC中的一个时刻

Instant instant = Instant.now() ;
不幸的是,编写JDBC 4.2规范的人莫名其妙地需要对
OffsetDateTime
的支持,而不是对两个更常用的类
Instant
ZonedDateTime
的支持。不管怎样,如果您的特定JDBC驱动程序不支持
Instant
,我们可以轻松地来回转换

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ; 
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
或者,跳过
即时

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ; 
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
发送到数据库

myPreparedStatement.setObject( … , odt ) ;
检索

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
这里的
LocalDateTime
类是错误的。该类表示不带时区上下文或UTC偏移量的日期和时间。所以这个类不能代表一个时刻,时间线上的一个点。所以这个类不能用来记录什么时候发生了什么。我想不出调用
LocalDateTime.now()
是正确的做法


这些主题已经在许多现有的问题和答案中讨论过。搜索了解更多信息。

需要对
OffsetDateTime
的支持,而不是
Instant
zoneDateTime
:SQL标准只定义了对基于偏移的
时区类型的支持,因此JDBC也是如此。使用
Instant
不会保留任何已存储的偏移量信息,存储与使用偏移量为零的
OffsetDateTime
没有太大区别。@markrotVeel使用
ZoneOffset在
Instant
OffsetDateTime
之间来回转换。UTC
非常简单。为什么不要求JDBC驱动程序执行转换以方便调用程序的程序员呢?关于
ZonedDateTime
,感谢您的解释,这现在是有意义的。因为瞬间不是OffsetDateTime,并且选择仅使用直接映射到等效SQL标准类型的类型。