如何在UTC中插入时间戳

问题描述 投票:0回答:3

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

+-----------+----------+------+-----+---------+----------------+
| Field     | Type     | Null | Key | Default | Extra          |
+-----------+----------+------+-----+---------+----------------+
| ...       | ...      | ..   | ... | ...     | ...            |
| timestamp | datetime | YES  |     | NULL    |                |
| ...       | ...      | ..   | ... | ...     | ...            |
+-----------+----------+------+-----+---------+----------------+

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

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

Timestamp datetime = new Timestamp(new Date().getTime());
        

java.util.Date的文档指出:

虽然Date类的目的是体现协调通用 时间(UTC),它可能不准确,具体取决于主机 Java虚拟机环境。

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

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

java jdbc
3个回答
6
投票

tl;博士

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

示例代码片段。

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

MySQL 中的数据类型错误

假设时间戳采用 UTC 格式

你明白MySQL中的

DATETIME
在UTC中是不是吗? MySQL 中的该类型没有时区概念,也没有与 UTC 的偏移量。

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

TIMESTAMP
来跟踪 MySQL 中的时刻。

错误的 Java 类

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

java.sql.Timestamp
类。

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

Instant

Instant instant = Instant.now() ;

将 MySQL 中的列定义为类型

TIMESTAMP

可能能够通过 JDBC 驱动程序编写

Instant
。然而,JDBC 4.2 需要对
OffsetDateTime
的支持,但奇怪的是省略了对
Instant
的必要支持。没关系,我们可以轻松转换。

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

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

myPreparedStatement.setObject( … , odt ) ;

检索。

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

消除时区问题

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

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


关于 java.time

java.time框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如

java.util.Date
Calendar
SimpleDateFormat

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

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

您可以直接与数据库交换 java.time 对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。不需要字符串,不需要

java.sql.*
类。 Hibernate 5 和 JPA 2.2 支持 java.time.

从哪里获取java.time类?


5
投票

问)如何获取UTC时间戳

按如下方式进行:

ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Etc/UTC"));
Timestamp timestamp = Timestamp.valueOf(zdt.toLocalDateTime());

备注:

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

1
投票

您可以让 MySQL 使用此列定义插入时间戳

CREATE TABLE SOME_TABLE_NAME (
     SOME_COLUMN_NAME TIMESTAMP default CURRENT_TIMESTAMP
);
© www.soinside.com 2019 - 2024. All rights reserved.