Java JDBC:在UTC中插入时间戳
我的部分表定义(MySQL)如下所示:Java JDBC:在UTC中插入时间戳,java,jdbc,Java,Jdbc,我的部分表定义(MySQL)如下所示: +-----------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+----------+------+-----+---------+----------------+ | ... | ... | .. | ...
+-----------+----------+------+-----+---------+----------------+
| 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中将列定义为typeTIMESTAMP
您可以通过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中使用了错误的数据类型。