【问题标题】:How to save correct date time with timezone when using jdbc使用 jdbc 时如何使用时区保存正确的日期时间
【发布时间】:2021-05-24 17:32:40
【问题描述】:

我正在使用 Java 和 JDBC 连接到 PostgreSQL 数据库。我在节省数据库时间时遇到问题。我的数据库有表学生,列看起来像

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 postgresql jdbc timezone


    【解决方案1】:

    您使用了错误的类和类型。

    永远不要使用 TimeZoneTimestamp 类。这些是 Java 最早版本中糟糕的日期时间类的一部分,几年前被 JSR 310 中定义的现代 java.time 类所取代。特别被 ZoneIdInstant/ 取代OffsetDateTime.

    在 Postgres 中,确保您的 created_at 列的类型为 TIMESTAMP WITH TIME ZONE,而不是 WITHOUT

    通常最好将当前时刻捕获为Instant。该类代表 UTC 中的时刻。

    Instant instant = Instant.now() ;
    

    不幸的是,编写 JDBC 4.2 规范的人莫名其妙地需要对 OffsetDateTime 的支持,而不是对两个更常用的类 InstantZonedDateTime 的支持。无论如何,如果您的特定 JDBC 驱动程序不支持Instant,我们可以轻松地来回转换。

    OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ; 
    

    或者,跳过Instant

    OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
    

    发送到数据库。

    myPreparedStatement.setObject( … , odt ) ;
    

    检索。

    OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
    

    LocalDateTime 类在这里是错误的。该类表示没有时区上下文或与 UTC 偏移的日期和时间。所以那个类不能代表一个时刻,时间轴上的一个点。所以这个类不能用来记录什么时候发生的事情。我想不出任何情况下调用LocalDateTime.now() 是正确的做法。

    这些主题已在许多现有的问答中得到解决。搜索以了解更多信息。

    【讨论】:

    • 要求支持OffsetDateTime 而不是InstantZonedDateTime 并没有什么莫名其妙的:SQL 标准只定义了对基于偏移量的WITH TIME ZONE 类型的支持,因此JDBC 也是如此。使用Instant 不会保留任何存储的偏移信息,并且存储与使用偏移为零的OffsetDateTime 没有太大区别。
    • @MarkRotteveel 在InstantOffsetDateTimeZoneOffset.UTC 之间来回转换非常简单。为了调用程序员的方便,为什么不要求 JDBC 驱动程序执行该转换呢?关于ZonedDateTime,谢谢你的解释,现在说得通了。
    • 因为 Instant 不是 OffsetDateTime,所以选择只使用直接映射到等效 SQL 标准类型的类型。
    猜你喜欢
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-31
    相关资源
    最近更新 更多