Java JDBC:在UTC中插入时间戳

Java JDBC:在UTC中插入时间戳,java,jdbc,Java,Jdbc,我的部分表定义(MySQL)如下所示: +-----------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+----------+------+-----+---------+----------------+ | ... | ... | .. | ...

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

+-----------+----------+------+-----+---------+----------------+
| Field     | Type     | Null | Key | Default | Extra          |
+-----------+----------+------+-----+---------+----------------+
| ...       | ...      | ..   | ... | ...     | ...            |
| timestamp | datetime | YES  |     | NULL    |                |
| ...       | ...      | ..   | ... | ...     | ...            |
+-----------+----------+------+-----+---------+----------------+
Timestamp datetime = new Timestamp(new Date().getTime());
        
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Etc/UTC"));
Timestamp timestamp = Timestamp.valueOf(zdt.toLocalDateTime());
我想使用JDBC更新时间戳字段。假设时间戳位于UTC

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

+-----------+----------+------+-----+---------+----------------+
| Field     | Type     | Null | Key | Default | Extra          |
+-----------+----------+------+-----+---------+----------------+
| ...       | ...      | ..   | ... | ...     | ...            |
| timestamp | datetime | YES  |     | NULL    |                |
| ...       | ...      | ..   | ... | ...     | ...            |
+-----------+----------+------+-----+---------+----------------+
Timestamp datetime = new Timestamp(new Date().getTime());
        
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Etc/UTC"));
Timestamp timestamp = Timestamp.valueOf(zdt.toLocalDateTime());
以下国家的文件:
尽管Date类旨在反映协调世界时(UTC),但根据Java虚拟机的主机环境,它可能无法准确反映协调世界时。

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


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

Q) 如何获取UTC时间戳

按如下方式操作:

+-----------+----------+------+-----+---------+----------------+
| Field     | Type     | Null | Key | Default | Extra          |
+-----------+----------+------+-----+---------+----------------+
| ...       | ...      | ..   | ... | ...     | ...            |
| timestamp | datetime | YES  |     | NULL    |                |
| ...       | ...      | ..   | ... | ...     | ...            |
+-----------+----------+------+-----+---------+----------------+
Timestamp datetime = new Timestamp(new Date().getTime());
        
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Etc/UTC"));
Timestamp timestamp = Timestamp.valueOf(zdt.toLocalDateTime());
注意事项:

  • 由于您希望使用时间戳,我建议您将字段类型更改为
    timestamp
    。查看更多详细信息
  • 停止使用过时的
    java.util
    date-time API并切换到

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

    CREATE TABLE SOME_TABLE_NAME (
         SOME_COLUMN_NAME TIMESTAMP default CURRENT_TIMESTAMP
    );
    
    tl;博士 MySQL中的数据类型错误,Java中的类错误

    • 写入类型为的列,而不是
      DATETIME
    • 使用而不是
      java.sql.Timestamp
    示例代码片段

    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中没有UTC?MySQL中的这种类型没有时区的概念,也没有UTC的偏移量

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

    错误的Java类 您使用的是与最早版本的Java捆绑在一起的糟糕的日期时间类。这些类被Java8和更高版本中的现代java.time类所取代,如JSR310中所定义。永远不要使用
    java.sql.Timestamp

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

    Instant instant = Instant.now() ;
    
    在MySQL中将列定义为type
    TIMESTAMP

    您可以通过JDBC驱动程序编写
    即时
    。然而,JDBC4.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 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

    要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

    该项目现已启动,建议迁移到类

    您可以直接与数据库交换java.time对象。使用兼容的或更高版本。不需要字符串,也不需要
    java.sql.*
    类。Hibernate5和JPA2.2支持java.time

    从哪里获得java.time类

    • 、和更高版本-标准Java API的一部分,带有捆绑实现
    • Java9添加了一些次要功能和修复
    • 大多数java.time功能都在中向后移植到Java6和Java7
    • 更高版本的Android捆绑包实现了java.time类

    • 对于早期的Android(注意类型的描述。在MySQL中,
      datetime
      是一种类型,它将存储没有时区信息的值,您需要知道使用哪个时区来存储/检索它,而
      timestamp
      将始终将值存储在数据库中作为UTC,您可以灵活地使用哪个时区来存储重新或检索该值。请参见这里的
      OffsetDateTime
      ZonedDateTime
      更合适。而且
      OffsetDateTime
      可以直接发送到数据库,因此不需要麻烦的遗留类
      java.sql.Timestamp
      。JDBC仅在
      Timestamp>上定义对
      java.time.OffsetDateTime
      的支持使用时区
      列。您是否验证了
    getObject(..,OffsetDateTime.class)
    在这种情况下是否有效?@markrotVeel正如我在回答中三次提到的,问题中的数据库在MySQL中使用了错误的数据类型。