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

2022-09-01 20:30:02

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

鉴于

1. 时区: GMT+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. JavaDoc for System.currentTimeMillis() 它告诉返回值将是当前时间和 1970 年 1 月 1 日 UTC 午夜之间的差值(以毫秒为单位)。

那么,为什么

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

答案 1

两者都返回自 Unix 时代以来的毫秒数。这不是“在任何特定的时区”,尽管Unix时代通常表示为“1970年1月1日UTC的午夜”。但瞬间只是时间上的瞬间,无论你身处哪个时区,它都是一样的——但它会反映不同的当地时间。System.currentTimeMillis()Instant.toEpochMilli()

的输出不同,因为您说的是“获取本地日期和时间,并将其转换为即时,就好像它在 UTC 时区中一样” - 即使您在 UTC+3 时区中创建时,您隐式地这样做了...这就是为什么它是“错误的”。LocalDateTime.atZone(UTC)LocalDateTime

LocalDateTime.now()采用系统默认时区的本地日期和时间。因此,如果您的时区是 UTC+3,则当前时间的即时是 2015-10-06T16:57:00Z,则将返回 。让我们称之为...LocalDateTime.now().2015-10-06T19:57:00localNow

因此将返回一个表示 2015-10-06T19:57:00+03 - 换句话说,相同的本地日期/时间,但“知道”它比 UTC 早 3 小时...所以将返回一个代表 2015-10-06T16:57:00Z.太好了 - 我们仍然有当前的日期/时间。localNow.atZone(ZoneOffset.of("+3"))ZonedDateTimetoInstant()Instant

但将返回一个代表 2015-10-06T19:57:00Z - 换句话说,相同的本地日期/时间,但“认为”它已经在 UTC 中...所以将返回一个代表 2015-10-06T19:57:00Z..这根本不是当前时间(在三个小时内)。localNow.atZone(ZoneOffset.UTC)ZonedDateTimetoInstant()Instant


答案 2

简短版本

没有办法计算,你需要指定一个时区。使用时区,您可以获得一个并且可以计算LocalDateTime -> InstantZonedDateTimeZonedDateTime -> Instant

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

长版本

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

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

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

本地日期时间

如果没有其他信息(如偏移量或时区),它就无法表示时间线上的某个时刻。

ZonedDateTime

此类处理从 LocalDateTime 的本地时间线到 Instant 的即时时间线的转换。两条时间线之间的差值是 UTC/格林威治的偏移量,由 ZoneOffset 表示。

要获得即时,您需要先将LocalDateTime转换为ZonedDateTime。如果您正确地做到了这一点(通过声明正确的时区),您的即时将同意System.currentTimeMillis()。

System.currentTimeMillis()

当前时间与 1970 年 1 月 1 日 UTC 午夜之间的差异(以毫秒为单位)。

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

如果您的时区是GMT + 3,则ZonedDateTime.toInstant()将为您提供正确的即时,因此同意System.currentTimeMillis()

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

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