ZonedDateTime 的 GMT 和 UTC 是否相同?

kom*_*mer 1 java timezone datetime java-time zoneddatetime

我已经实现了一个供国际使用的 API,我正在尝试以 GMT 时间以 ISO 8601 格式返回对象的日期。现在我这样做

ZonedDateTime.withZoneSameInstant(ZoneOffset.UTC)
Run Code Online (Sandbox Code Playgroud)

但我知道 UTC 和 GMT 不是一回事。

稍后我将为每个用户分配他们喜欢的 Locale 并返回他们的 Locale ,但现在我想以 GMT 的方式执行此操作,但我不知道如何以正确的方式执行此操作

Ole*_*.V. 5

TL; 博士

要在ZonedDateTimeUTC和GMT有不同的名称,但同一区域的规则,所以时间总是会在UTC和GMT一样。

理论

最初 GMT 和 UTC 的定义不同。UTC 时间和 GMT 时间之间从未超过一秒。由于 UTC 已成为无处不在的时间锚点,GMT 有时被松散地用于表示 UTC,因此区分更加模糊。

练习:ZonedDateTme

AZonedDateTime使用 aZoneId作为其时区,因此您的问题等于询问ZoneIdGMT 和 UTC 是否相同。让我们先看看它们的外观:

    ZoneId utc = ZoneId.of("Etc/UTC");
    System.out.println("Etc/UTC:        " + utc);

    ZoneId gmt = ZoneId.of("Etc/GMT");
    System.out.println("Etc/GMT:        " + gmt);

    ZoneId utcNormalized = utc.normalized();
    System.out.println("UTC normalized: " + utcNormalized);

    ZoneOffset utcAsOffset = ZoneOffset.UTC;
    System.out.println("UTC as offset:  " + utcAsOffset);

    ZoneId gmtNormalized = gmt.normalized();
    System.out.println("GMT normalized: " + gmtNormalized);
Run Code Online (Sandbox Code Playgroud)

输出是:

Etc/UTC:        Etc/UTC
Etc/GMT:        Etc/GMT
UTC normalized: Z
UTC as offset:  Z
GMT normalized: Z
Run Code Online (Sandbox Code Playgroud)

前两行告诉我们,ZoneId确实可以区分 GMT 和 UTC。它们都是具有时区 ID 的有效时区。

normalized()我使用的3号和5号线的承诺方法将转换ZoneIdZoneOffset ,如果时区采用恒定偏移。在这两种情况下,我们都会得到零回的偏移量。所以这里ZoneId不区分。

为了更仔细地检查这个问题:

    System.out.println("Are GMT and UTC the same? " + utc.equals(gmt));
    System.out.println("Are GMT and UTC the same? "
            + utcNormalized.equals(gmtNormalized));
    System.out.println("Are GMT and UTC the same? "
            + utc.getRules().equals(utcAsOffset.getRules()));
Run Code Online (Sandbox Code Playgroud)
Are GMT and UTC the same? false
Are GMT and UTC the same? true
Are GMT and UTC the same? true
Run Code Online (Sandbox Code Playgroud)

所以ZoneId对象是不相等的,ZonedDateTime即使它们具有相同的日期和时间,使用这两者的对象也不相等。但是我们从它们那里得到了相同的偏移量,并且它们具有相等的区域规则,也就是说,它们将始终具有相同的时间。

Java 代码的后果

这一行来自您的问题:

ZonedDateTime.withZoneSameInstant(ZoneOffset.UTC)
Run Code Online (Sandbox Code Playgroud)

这是正确的,没有令人信服的理由为什么你应该这样做。如果您愿意,由于 Java 将 UTC 视为区域偏移量,您可以OffsetDateTime改为转换为。我以某种方式认为它不如ZonedDateTime.

如果您希望ZonedDateTime以 GMT 而不是 UTC 打印,请使用ZoneId.of("Etc/GMT"). 在这里,我使用了持有该时区之前的变量:

    ZonedDateTime zdtGmt = ZonedDateTime.now(ZoneId.of("Asia/Istanbul"))
            .withZoneSameInstant(gmt);
    System.out.println("Time in GMT: " + zdtGmt);
    DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL)
            .withLocale(Locale.forLanguageTag("tr"));
    System.out.println("Time in GMT: " + zdtGmt.format(formatter));
Run Code Online (Sandbox Code Playgroud)

刚才的输出:

Time in GMT: 2020-05-16T09:34:05.253696Z[Etc/GMT]
Time in GMT: 16 May?s 2020 Cumartesi 09:34:05 Greenwich Ortalama Saati
Run Code Online (Sandbox Code Playgroud)

你进一步写道:

稍后我将为每个用户分配他们喜欢的语言环境,然后返回他们的语言环境……

Locale在这里不相关。区域设置和时区是正交概念。例如,来自土耳其的访问上海的人可能想要使用土耳其语言环境和上海时区。无法从语言环境中推断出时区(至少没有声音)。您可能需要考虑为每个用户分配一个首选时区。