我提供现代化的答案。
Java.time和JDBC 4.2
您应该避免使用Timestamp类。它设计不良且非常令人困惑,是对已经设计不良的java.util.Date类的真正破解。其他答案导致与rve答案中记录的比较结果不同,我认为这说明了混淆非常明显。您已经在使用java.time,这是现代Java日期和时间API,并且只要您拥有符合JDBC 4.2标准的JDBC驱动程序,就可以并且应该坚持使用java.time中的类。
最好将其存储为带有时区的时间戳
像您所说,将日期和时间以UTC格式存储在数据库中是一个好的建议性做法。如果可以的话,请更改数据库中的数据类型为"timestamp with time zone"。虽然这不会存储时区(尽管名称如此),但它确保数据库也“知道”时间戳是UTC,这已经防止了许多错误。下一个优点是(如果我理解正确),您可以直接存储您的OffsetDateTime,并自动进行到UTC的转换。
OffsetDateTime odt = OffsetDateTime.of(
2015, 6, 4, 19, 15, 43, 210987000, ZoneOffset.ofHours(1));
PreparedStatement stmt = yourDbConnection.prepareStatement(
"insert into your_table (your_timestamp_with_time_zone) values (?);");
stmt.setObject(1, odt);
stmt.executeUpdate();
如果你想在Java代码中更清晰地表明时间是以UTC存储的,请先进行显式转换:
odt = odt.withOffsetSameInstant(ZoneOffset.UTC);
如果您的数据库存储的时间戳(timestamp)没有时区
如果您的数据库中的数据类型只是简单的 timestamp
(没有时区)(不推荐使用),在Java端应该使用 LocalDateTime
类型。我会按以下方式进行转换为UTC:
LocalDateTime ldt = odt.withOffsetSameInstant(ZoneOffset.UTC).toLocalDateTime();
System.out.println("UTC datetime = " + ldt);
输出结果为:
UTC日期时间 = 2015-06-04T18:15:43.210987
将其存储到数据库中与之前相似:
PreparedStatement stmt = yourDbConnection.prepareStatement(
"insert into your_table (your_timestamp) values (?);");
stmt.setObject(1, ldt);
dateTime
包含2015-10-23T12:44:43Z
,并且您在时区 UTC+2 中,则timestamp
将保存2015-10-23 14:44:43.0
,与答案中提供的结果(2015-10-23 12:44:43.0
)不同。 - rvejava.util.Date
、Time
和Timestamp
时,始终使用系统时区而非 UTC。这使得它无法表示 LocalDateTime,但至少可以获得精确的 Instant。 - Eugen Pechanec