如何获取当前本地时间的 UTC 转换 Java 时间戳?

How can I get the UTC-converted Java timestamp of current local time?

有人可以帮忙获取 UTC 转换的 Java 当前本地时间的时间戳吗? 主要目标是获取当前日期和时间,转换成 UTC 时间戳,然后作为时间戳 yyyy-MM-dd hh:mm:ss[.nnnnnnnnn].

存储在 Ignite 缓存中

我的尝试是 Timestamp.from(Instant.now())。但是,它仍然考虑我的本地时区 +03:00。结果我得到 '2020-02-20 10:57:56',而不是理想的 '2020-02-20 07:57:56'

如何获得 UTC 转换时间戳?

你可以这样做:

LocalDateTime localDateTime = Instant.now().atOffset(ZoneOffset.UTC).toLocalDateTime();
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
    System.out.println(localDateTime.format(formatter));

不要使用时间戳

您很可能不需要 Timestamp。这很好,因为 Timestamp class 设计不佳,确实是在已经设计不佳的 Date class 之上的真正 hack。两个 classes 也早就过时了。相反,将近 6 年前我们得到了 java.time,现代的 Java 日期和时间 API。从 JDBC 4.2 开始,这也适用于您的 JDBC 驱动程序,也适用于您的现代 JPA 实现。

使用 OffsetDateTime

对于时间戳,数据库中推荐的数据类型是 timestamp with time zone。在本例中,Java 使用偏移量为零(即 UTC)的 OffsetDateTime。例如:

    OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
    System.out.println(now);

    PreparedStatement statement = yourDatabaseConnection
            .prepareStatement("insert into your_table (tswtz) values (?);");
    statement.setObject(1, now);
    int rowsInserted = statement.executeUpdate();

刚才 System.out.println() 的示例输出:

2020-02-22T13:04:06.320Z

如果您的数据库时间戳没有时区,则使用 LocalDateTime

根据您的问题,我的印象是您数据库中的数据类型是 timestamp,没有时区。它只是第二好的选择,但你可以传递一个 LocalDateTime 给它。

    LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);

其余同上。示例输出:

2020-02-22T13:05:08.776

如果你确实需要一个老式的java.sql.Timestamp

您要求 Timestamp UTC 时间。 Timestamp 在 UTC 中总是 。更准确地说,它是一个独立于时区的时间点,因此将其转换为不同的时区是没有意义的。在内部,它被实现为自纪元以来的毫秒数和纳秒数。纪元定义为 1970 in UTC.

的第一个时刻

不过 Timestamp class 令人困惑 class。可能让您感到困惑的一件事是当您打印它时,从而隐式调用它的 toString 方法。 toString 方法使用 JVM 的默认时区来呈现字符串,因此打印您当地时区的时间。令人困惑。如果 SQL 中的数据类型是没有时区的 timestamp,您的 JDBC 驱动程序很可能会解释您时区中的 Timestamp 以转换为 SQL timestamp。在您的情况下,这是不正确的,因为您的数据库使用 UTC(推荐做法)。我可以想到三种可能的解决方案:

  1. 一些数据库引擎允许您在会话中设置时区。我自己没有任何经验,这是我读过的东西;但它可能会强制执行从 Java Timestamp 到 UTC 中的 SQL timestamp 的正确转换。
  2. 您可能在 Java 中进行了错误的转换,以补偿在 Java 和 SQL 之间执行的相反的错误转换。这是一个 hack,不是我想要在我的代码中包含的东西。我把它作为最后的手段。

        LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
        Timestamp ts = Timestamp.valueOf(now);
        System.out.println(ts);
    

    2020-02-22 13:05:08.776

    您注意到它只出现与上面的 UTC 时间一致。这与您从 Vipin Sharma 的回答中得到的结果相同,除了 (1) 我的代码更简单并且 (2) 您获得更高的精度,包括秒的分数。

  3. 您的数据库是否以 UTC 格式生成当前时间戳而不是 Java。

链接

尽管 Ignite docs say 你可以在 24 小时内通过。 文档说 yyyy-MM-dd hh:mm:ss[.nnnnnnnnn] 所以你可能会在你的代码中使用它来格式化你的日期,但这会导致中午之后的时间是错误的。相反,请使用 yyyy-MM-dd HH:mm:ss[.nnnnnnnnn].

格式化您的日期

注意大写 HH。如果您现在使用 ZonedDateTime 或 Joda 的 DateTime 使用 UTC now(UTC) 调用,然后 toString("yyyy-MM-dd HH:mm:ss") 将以 UTC 存储正确的时间。