JDBC:在 UTC 中插入时间戳

San*_*eep 5 java jdbc

我的部分表定义(MySQL)如下所示:

+-----------+----------+------+-----+---------+----------------+
| Field     | Type     | Null | Key | Default | Extra          |
+-----------+----------+------+-----+---------+----------------+
| ...       | ...      | ..   | ... | ...     | ...            |
| timestamp | datetime | YES  |     | NULL    |                |
| ...       | ...      | ..   | ... | ...     | ...            |
+-----------+----------+------+-----+---------+----------------+
Run Code Online (Sandbox Code Playgroud)

我想使用 JDBC 更新时间戳字段。假设时间戳是UTC

在我的 Java 代码中,我按如下方式获取时间戳字段:

Timestamp datetime = new Timestamp(new Date().getTime());
        
Run Code Online (Sandbox Code Playgroud)

java.util.Date的文档指出:
尽管 Date 类旨在反映协调世界时 (UTC),但它可能不会完全如此,具体取决于 Java 虚拟机的主机环境。

不幸的是,在我的 Windows 10 环境(java 版本“1.8.0_231”)中,Date 对象反映了我的本地时区。因此,添加到数据库中的时间戳是针对本地时区的,而不是 UTC。


问)如何获取 UTC 时间戳,以便将正确的值添加到数据库中?

Bas*_*que 7

太长了;博士

\n

MySQL 中的数据类型错误,Java 中的类错误。

\n\n

示例代码片段。

\n
myPreparedStatement\n.setObject( \n    \xe2\x80\xa6 ,                       // Specify which placeholder `?` to fill-in.\n    OffsetDateTime            // JDBC 4.2 and later requires a JDBC driver support exchanging `java.time.OffsetDateTime` objects with the database.\n    .now( ZoneOffset.UTC )    // Capture the current moment as seen in UTC (an offset of zero hours-minutes-seconds). \n)\n
Run Code Online (Sandbox Code Playgroud)\n

MySQL 中的数据类型错误

\n
\n

假设时间戳采用 UTC

\n
\n

你知道DATETIMEMySQL中的数据不是UTC吗?MySQL 中的该类型没有时区概念,也没有相对 UTC 的偏移量。

\n

如果您正在跟踪时刻、时间线上的特定点,则 MySQL 中的数据类型错误。您应该使用TIMESTAMPMySQL 来跟踪时刻。

\n

错误的 Java 类

\n

您正在使用与最早版本的 Java 捆绑在一起的糟糕的日期时间类。这些类在 Java 8 及更高版本中被现代java.time类取代,如 JSR 310 中所定义。切勿使用该类java.sql.Timestamp

\n

要获取 UTC 中的当前时刻,请使用Instant

\n
Instant instant = Instant.now() ;\n
Run Code Online (Sandbox Code Playgroud)\n

将 MySQL 中的列定义为 type TIMESTAMP

\n

也许Instant可以通过 JDBC 驱动程序编写一个。然而,JDBC 4.2 需要OffsetDateTimeInstant. 没关系,我们可以轻松转换。

\n
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;\n
Run Code Online (Sandbox Code Playgroud)\n

使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序,通过准备好的语句将其写入数据库。

\n
myPreparedStatement.setObject( \xe2\x80\xa6 , odt ) ;\n
Run Code Online (Sandbox Code Playgroud)\n

恢复。

\n
OffsetDateTime odt = myResultSet.getObject( \xe2\x80\xa6 , OffsetDateTime.class ) ;\n
Run Code Online (Sandbox Code Playgroud)\n

消除时区问题

\n

如果您遵循此处的代码,您将不会遇到时区问题。

\n
    \n
  • 这些代码都不依赖于 JVM\xe2\x80\x99s 当前的默认时区。
  • \n
  • 此代码都不依赖于数据库服务器\xe2\x80\x99s当前的默认时区。
  • \n
\n
\n

Java(传统和现代)和标准 SQL 中的日期时间类型表

\n
\n

关于java.time

\n

java.time框架内置于 Java 8 及更高版本中这些类取代了麻烦的旧遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

\n

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

\n

Joda -Time项目现在处于维护模式,建议迁移到java.time类。

\n

您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC 驱动程序。不需要字符串,不需要类。Hibernate 5 和 JPA 2.2 支持java.timejava.sql.*

\n

从哪里获取 java.time 类?

\n\n


Arv*_*ash 6

问)如何获取 UTC 时间戳

请按如下方式进行:

ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Etc/UTC"));
Timestamp timestamp = Timestamp.valueOf(zdt.toLocalDateTime());
Run Code Online (Sandbox Code Playgroud)

笔记:

  1. 由于您想使用时间戳,我建议您将字段类型更改为TIMESTAMP. 检查以获取更多详细信息。
  2. 停止使用过时的java.util日期时间 API 并切换到现代日期时间 API