JSR 310 :: System.currentTimeMillis() 与 Instant.toEpochMilli() :: 时区

JSR 310 :: System.currentTimeMillis() vs Instant.toEpochMilli() :: TimeZone

您能否阐明如何为默认系统时区和给定时区获取以毫秒为单位的正确纪元时间。

给定

1。时区:格林威治标准时间+3

2。以下代码片段:

import java.time.*;

public class Main {        
    public static void main(String[] args) {
        System.out.println(LocalDateTime
            .now()
            .atZone(ZoneOffset.UTC)
            .toInstant()
            .toEpochMilli()
        );
        System.out.println(LocalDateTime
            .now()
            .atZone(ZoneOffset.of("+3"))
            .toInstant()
            .toEpochMilli()
        );
        System.out.println(System.currentTimeMillis());
    }
}

3。输出:

1444158955508
1444148155508
1444148155508

4。 System.currentTimeMillis() 的 JavaDoc 告诉返回值将是 当前时间与 1970 年 1 月 1 日午夜 UTC 之间的差异,以毫秒为单位。

那么,为什么

  1. LocalDateTimeGMT+3 的输出与 System.currentTimeMillis() 相同,尽管 System.currentTimeMillis() 的文档提到 UTC?
  2. LocalDateTimeUTC 的输出与 System.currentTimeMillis() 不同,尽管 System.currentTimeMillis() 的文档提到 UTC?

System.currentTimeMillis()Instant.toEpochMilli() return 自 Unix 纪元以来的毫秒数。这不是 "in" 任何特定时区,尽管 Unix 纪元通常表示为 "midnight on January 1st 1970, UTC"。但是瞬间只是时间上的瞬间,无论你在哪个时区都是一样的 - 但它会反映不同的当地时间。

LocalDateTime.atZone(UTC) 的输出不同,因为您说的是 "Take the local date and time, and convert it to an instant as if it were in the UTC time zone" - 即使当您创建 LocalDateTime 时,您是在 UTC+3 时区中隐含地这样做的...这就是为什么 "wrong".

LocalDateTime.now()采用系统默认时区中的本地日期和时间。所以如果你的时区是UTC+3,当前时间是2015-10-06T16:57:00Z,那么LocalDateTime.now()就会return.2015-10-06T19:57:00。我们称之为 localNow...

所以localNow.atZone(ZoneOffset.of("+3"))会return一个ZonedDateTime表示2015-10-06T19:57:00+03——换句话说,同一个本地date/time,但是"knowing" 比 UTC 早 3 小时...所以 toInstant() 将 return 和 Instant 代表 2015-10-06T16:57:00Z。太好了 - 我们还有当前的 date/time.

但是localNow.atZone(ZoneOffset.UTC)会return一个代表2015-10-06T19:57:00Z的ZonedDateTime——换句话说,同一个本地date/time,但是"thinking" 它已经在 UTC 中了...所以 toInstant() 将 return 一个 Instant 代表 2015-10-06T19:57:00Z.. 这根本不是当前时间(三个小时后)。

短版:

无法计算LocalDateTime -> Instant,您需要指定时区。 使用时区,您可以获得 ZonedDateTime 并且可以计算 ZonedDateTime -> Instant

Instant == System.currentTimeMillis() 如果 ZonedDateTime 的时区等于系统默认时区。

长版:

LocalDateTime 是您时钟上的时间(加上日期信息)。如果您不告诉我们您所在的时区,这是不够的。东京的 13:00 点与巴黎的 13:00 点不同。

将时区添加到 LocalDateTime 后,您将获得 ZonedDateTime,我们可以知道您实际处于哪个时间点。例如。你 13:00 点钟在东京还是在巴黎?

要获得正确的 Instant,ZonedDateTime 的时区需要正确。如果东京是 13:00 点,但你声称自己是巴黎 13:00 点,你就会得到错误的 Instant。

LocalDateTime:

It cannot represent an instant on the time-line without additional information such as an offset or time-zone.

ZonedDateTime:

This class handles conversion from the local time-line of LocalDateTime to the instant time-line of Instant. The difference between the two time-lines is the offset from UTC/Greenwich, represented by a ZoneOffset.

要获得 Instant,您需要先将 LocalDateTime 转换为 ZonedDateTime。如果你这样做正确(通过说明正确的时区)你的 Instant 将同意 System.currentTimeMillis().

System.currentTimeMillis():

the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.

  1. LocalDateTime 在 GMT+3 的输出与 System.currentTimeMillis() 相同,尽管 System.currentTimeMillis() 的文档提到了 UTC?

如果您的时区是 GMT+3,那么 ZonedDateTime.toInstant() 会给您正确的 Instant,因此同意 System.currentTimeMillis()

  1. UTC 时 LocalDateTime 的输出不同于 System.currentTimeMillis(),尽管 System.currentTimeMillis() 的文档提到 UTC?

如果你的时区是不是 UTC,那么ZonedDateTime.toInstant()会给你一个不正确的即时。

System.out.println("Output 1 : " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("Output 2 : " + System.currentTimeMillis());

输出 1:1576047664910

输出 2:1576047664911