将OffsetDateTime转换为UTC时间戳

时间:2015-06-04 18:15:39

标签: java

我有一个java.time.OffsetDateTime,我想将其转换为java.sql.Timestamp。由于Timestamp不存储任何偏移信息,因此我将以UTC格式存储数据库中的所有日期/时间。

如何将OffsetDateTime转换为UTC中的Timestamp

修改

我相信这是答案,但似乎是转向UTC的错综复杂的方式:

OffsetDateTime dateTime = OffsetDateTime.now();
Timestamp timestamp = Timestamp.valueOf(dateTime.atZoneSameInstant(ZoneId.of("Z")).toLocalDateTime());

4 个答案:

答案 0 :(得分:13)

这是一种进行转换并确保使用UTC的方法。我认为比使用纪元秒提出的解决方案更清洁。

Timestamp test = Timestamp.valueOf(entityValue.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime());

答案 1 :(得分:8)

另一种解决方案是:

Timestamp.valueOf(LocalDateTime.ofInstant(dateTime.toInstant(), ZoneOffset.UTC));

它将dateTime转换为UTC,删除时区信息,然后将结果转换为Timestamp。它仍然令人费解,但恕我直言,它有点清洁。

只需使用toInstance()toEpochSeconds()即可使用提供的偏移量调整结果。

以下显示了此测试结果和其他答案:

OffsetDateTime dateTime = 
    OffsetDateTime.of(2015, 10, 23, 12, 44, 43, 0, ZoneOffset.UTC);
    // OffsetDateTime.of(2015, 10, 23, 12, 44, 43, 0, ZoneOffset.ofHours(-5));

err.println("dateTime            = " 
    + dateTime
);

err.println("as LocalDateTime    = " 
    + dateTime.toLocalDateTime()
);

err.println("as timestamp (mine) = " 
    + Timestamp.valueOf(LocalDateTime.ofInstant(dateTime.toInstant(), ZoneOffset.UTC))
);

err.println("@Cheetah (correct)  = " 
    + Timestamp.valueOf(dateTime.atZoneSameInstant(ZoneId.of("Z"))
        .toLocalDateTime())
);

err.println("@Notso (wrong)      = " 
    + Timestamp.from(dateTime.toInstant())
);

err.println("@Glorfindel (wrong) = " 
    + new Timestamp(1000 * dateTime.toEpochSecond())
);

给出以下结果(我的时区是CET):

(with ZoneOffset.UTC)
dateTime            = 2015-10-23T12:44:43Z
as LocalDateTime    = 2015-10-23T12:44:43
as timestamp (mine) = 2015-10-23 12:44:43.0
@Cheetah (correct)  = 2015-10-23 12:44:43.0
@Notso (wrong)      = 2015-10-23 14:44:43.0
@Glorfindel (wrong) = 2015-10-23 14:44:43.0

(with ZoneOffset.ofHours(-5))
dateTime            = 2015-10-23T12:44:43-05:00
as LocalDateTime    = 2015-10-23T12:44:43
as timestamp (mine) = 2015-10-23 17:44:43.0
@Cheetah (correct)  = 2015-10-23 17:44:43.0
@Notso (wrong)      = 2015-10-23 19:44:43.0
@Glorfindel (wrong) = 2015-10-23 19:44:43.0

(Notso上面的版本是在2016年2月17日编辑之前)

答案 2 :(得分:3)

使用.toEpochSecond()从参考日期(以UTC为单位)获取秒数,乘以1000并将其传递给Timestamp构造函数(因为它需要毫秒)。

new Timestamp(1000 * offsetDateTime.toEpochSecond());

答案 3 :(得分:1)

我正在提供现代的答案。

java.time和JDBC 4.2

您应该避免使用Timestamp类。它设计得很差而且很令人困惑,是在已经设计不完善的java.util.Date类之上的真正黑客。我认为,其他答案会导致不同的结果,正如我认为rve的比较所证明的那样,这一事实很好地说明了这种困惑。您已经在使用现代Java日期和时间API java.time中的OffsetDateTime,并且已经获得了兼容JDBC 4.2的JDBC驱动程序,那么您可以并且应该坚持使用java.time中的类。

最好存储为timestamp with time zone

按照您的意愿在数据库中以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);