【问题标题】:JSR 310 :: System.currentTimeMillis() vs Instant.toEpochMilli() :: TimeZoneJSR 310 :: System.currentTimeMillis() 与 Instant.toEpochMilli() :: TimeZone
【发布时间】:2015-10-06 16:51:16
【问题描述】:

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

给定

1。时区:GMT+3

2。以下代码sn -p:

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 告诉返回值将是 当前时间与 UTC 1970 年 1 月 1 日午夜之间的差异,以毫秒为单位。

那么,为什么

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

【问题讨论】:

    标签: java datetime timezone java-8 java-time


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • 我想在 Jon 的出色回答之上添加一个谦虚的评论。 LocalDateTime.now().atZone(ZoneOffset.UTC) 是对 ZonedDateTime 的转换调用,因为 LocalDateTime 没有区域。传递给 atZone() 方法的参数应该是用于派生 LocalDateTime 的原始(在此示例中为默认)时区,而不是作者可能打算退出的“to”时区,因为 Instant 没有时区。如果作者没有指定 TimeZone: GMT+3,他的问题就很难解决。
    【解决方案2】:
    System.out.println("Output 1 : " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
    System.out.println("Output 2 : " + System.currentTimeMillis());
    

    输出 1:1576047664910

    输出 2:1576047664911

    【讨论】:

    • 这段代码加上它的输出如何以及为什么为这个问题提供了一个答案,而这个问题已经有了一个公认的答案?你能解释一下吗?
    • @deHaar 问题是如何以毫秒为单位获得正确的纪元时间,所以我想 StinkyMadness 只是想为那些不想阅读的人提供一个简短的答案长答案。不过,我同意你的看法,如果没有最少的解释,答案并不是很有用。并且可以从Instant.now().toEpochMilli()以更简单的方式获得输出1。
    • @OleV.V 我不认为答案不好,但是当我发表评论时,它只是两行代码......
    • 大多数情况下我为“ZoneId.systemDefault()”添加了 2 行,如果我做了违反规则的事情,我在这里完全是新人。
    • 不,@StinkyMadness,您当然没有违反规则(顺便说一句,这需要一点时间来学习),感谢您的贡献。请自行决定是否要进一步改进您的答案——您有一个edit 链接以防万一。
    【解决方案3】:

    短版

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

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

    加长版

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

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

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

    LocalDateTime:

    如果没有偏移或时区等附加信息,它不能代表时间线上的瞬间。

    ZonedDateTime:

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

    要获得Instant,您需要先将 LocalDateTime 转换为 ZonedDateTime。如果您正确地执行了此操作(通过说明正确的时区),您的 Instant 将同意 System.currentTimeMillis()。

    System.currentTimeMillis():

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

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

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

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

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

    【讨论】:

    • ZonedDateTime.toInstant() 不应该将所述 ZonedDateTime 转换为 UTC,然后从中创建 Instant 吗?根据文档(以及我的经验,尽管使用的是 ThreetenBackport,而不是官方 API),我怀疑是这种情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-07
    • 1970-01-01
    • 2018-04-05
    • 2020-05-27
    • 2014-07-21
    • 2018-01-09
    相关资源
    最近更新 更多