java - 使用 jdbc 时如何使用时区保存正确的日期时间
问题描述
我正在使用 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"))
它对我没有帮助。
解决方案
您使用了错误的类和类型。
永远不要使用TimeZone
和Timestamp
类。这些是 Java 最早版本中糟糕的日期时间类的一部分,几年前被 JSR 310 中定义的现代java.time类所取代。特别由ZoneId
and Instant
/取代OffsetDateTime
。
在 Postgres 中,确保您的created_at
列的类型是TIMESTAMP WITH TIME ZONE
,而不是WITHOUT
。
通常最好将当前时刻捕获为Instant
. 该类代表 UTC 中的一个时刻。
Instant instant = Instant.now() ;
不幸的是,编写 JDBC 4.2 规范的人莫名其妙地需要对OffsetDateTime
两个更常用的类Instant
和ZonedDateTime
. 无论如何,如果您的特定 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()
是正确的做法。
这些主题已在许多现有的问题和答案中得到解决。搜索以了解更多信息。
推荐阅读
- javascript - 如何使用 babel 修改带有 AST 的 javascript 代码?
- android - Android 和 iOS 中的 google meet 和 Microsoft 团队的包名称是什么?
- multithreading - JMeter - 如何防止仪表板显示每个线程的请求 - 图表包含 1000 条线
- android-studio - BroadcastReceiver 触发更新另一个 Activity
- javascript - 动态创建一个内部包含数组的对象
- java - 试图将附件“csv文件”添加到gmail但没有成功,它的Android应用程序,我用我的手机作为模拟器进行调试
- amazon-cognito - 在一段时间不活动后自动禁用已确认的 AWS Cognito 用户账户
- c# - 根据工作日安排 Azure Function
- amazon-web-services - AWS - Boto -第一次服务后停止服务
- c# - 如何创建只能输入数字的文本框?