将OffsetDateTime转换为UTC时间戳

Che*_*tah 10 java

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

如何转换OffsetDateTimeTimestamp这是在UTC?

编辑:

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

OffsetDateTime dateTime = OffsetDateTime.now();
Timestamp timestamp = Timestamp.valueOf(dateTime.atZoneSameInstant(ZoneId.of("Z")).toLocalDateTime());
Run Code Online (Sandbox Code Playgroud)

Not*_*tso 13

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

Timestamp test = Timestamp.valueOf(entityValue.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime());
Run Code Online (Sandbox Code Playgroud)

  • 澄清上述注释以供将来参考:以前我的回答是建议Timestamp.from(entityValue.toInstant)会这样做.然而,虽然瞬间在epoch的时间轴上基本上是一个瞬间,但Timestamp.from(instant)会在@rve指出的当地时区返回它.因此,执行此操作并确保其保持UTC的方法是'Timestamp test = Timestamp.valueOf(entityValue.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime());' (3认同)

rve*_*rve 9

另一种解决方案是:

Timestamp.valueOf(LocalDateTime.ofInstant(dateTime.toInstant(), ZoneOffset.UTC));
Run Code Online (Sandbox Code Playgroud)

它将转换dateTime为UTC,剥离时区信息,然后将结果转换为a 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())
);
Run Code Online (Sandbox Code Playgroud)

它给出了以下结果(我的时区是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
Run Code Online (Sandbox Code Playgroud)

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


Glo*_*del 6

用于.toEpochSecond()从参考日期(在 UTC 中)获取秒数,乘以 1000 并将其传递给Timestamp构造函数(因为它期望毫秒)。

new Timestamp(1000 * offsetDateTime.toEpochSecond());
Run Code Online (Sandbox Code Playgroud)

  • 但这会丢失有关纳秒的信息 - 对吗? (2认同)
  • 如果你想要毫秒,只需使用`.toInstant().toEpochMilli()`。应该可以正常工作,直到 2038 年的某个时候...... (2认同)

Ole*_*.V. 6

我正在提供现代答案。

java.time 和 JDBC 4.2

你应该避免Timestamp上课。它的设计很差,而且非常混乱,是在已经设计得很差的java.util.Date课程之上的真正黑客。正如我认为 rve 的答案中的比较所记录的那样,其他答案会导致不同的结果,这一事实很好地说明了这种混淆。您已经在使用OffsetDateTimejava.time 中的现代 Java 日期和时间 API,并且如果您有一个 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();
Run Code Online (Sandbox Code Playgroud)

如果您想在 Java 代码中更清楚地说明时间是以 UTC 存储的,请先进行显式转换:

    odt = odt.withOffsetSameInstant(ZoneOffset.UTC);
Run Code Online (Sandbox Code Playgroud)

如果您的数据库存储timestamp没有时区

如果数据库中的数据类型仅仅是timestamp(没有时区)(不推荐),那么在 Java 端使用的类型是LocalDateTime. 我会像这样转换为UTC:

    LocalDateTime ldt = odt.withOffsetSameInstant(ZoneOffset.UTC).toLocalDateTime();
    System.out.println("UTC datetime        = " + ldt);
Run Code Online (Sandbox Code Playgroud)

输出是:

UTC 日期时间 = 2015-06-04T18:15:43.210987

存入数据库与之前类似:

    PreparedStatement stmt = yourDbConnection.prepareStatement(
            "insert into your_table (your_timestamp) values (?);");
    stmt.setObject(1, ldt);
Run Code Online (Sandbox Code Playgroud)

  • 当你说:“如果你的数据库中的数据类型只是一个时间戳(没有时区)(不推荐),那么在Java端使用的类型是LocalDateTime。”,这并不完全正确。如果您设置属性:hibernate.jdbc.time_zone=UTC,Hibernate 会将所有时间戳列视为 UTC,您可以在代码中使用 OffsetDateTime,Hibernate 将为您进行转换。 (2认同)