【问题标题】:Java 8 epoch-millis time stamp to formatted date, how?Java 8 epoch-millis时间戳到格式化日期,如何?
【发布时间】:2018-05-31 20:42:00
【问题描述】:

在 Java-8 之前,我习惯于始终将任何与 Epoch 相关的日期/时间保持为毫秒,并且只在退出时处理人类可读的日期/时间,即在 UI 或日志文件中,或者在解析用户时生成的输入。

我认为这对于 Java-8 来说仍然是安全的,现在我正在寻找最简洁的方法来从毫秒时间戳中获取格式化日期。我试过了

df = Dateformatter.ofPattern("...pattern...");
df.format(Instant.ofEpochMilli(timestamp))

但它在Instant.getLong(...) 中被Unsupported field: YearOfEra 炸毁,我理解了一半。现在用什么来代替Instant

LocalDateTime.ofEpoch(Instant, ZoneId) 似乎是错误的,因为我不想知道当地时间。我只想在应用格式化程序时查看本地时区。在内部它应该只是Instant

ZonedDateTime.ofInstant(Instant, ZoneId) 也是如此,我想仅在格式化时应用 ZoneId。但我注意到DateTimeFormatter 本身似乎不再处理时区,所以我认为我需要使用上述之一。

哪个是首选,为什么?或者我应该使用另一种方式将 epoch-millis 时间戳格式化为带时区的日期/时间?

【问题讨论】:

    标签: java datetime java-8 java-time


    【解决方案1】:

    Instant 不包含有关时区的任何信息,并且与其他地方不同,不会自动使用默认时区。因此,格式化程序无法确定年份是什么,因此会出现错误消息。

    因此,要格式化瞬间,您必须添加时区。这可以使用withZone(ZoneId) 直接添加到格式化程序中 - 无需手动转换为ZonedDateTime *:

    ZoneId zone = ZoneId.systemDefault();
    DateTimeFormatter df = DateTimeFormatter.ofPattern("...pattern...").withZone(zone);
    df.format(Instant.ofEpochMilli(timestamp))
    

    * 很遗憾,在早期的 Java 8 版本中,DateTimeformatter.withZone(ZoneId) 方法不起作用,但是现在已经修复了这个问题,所以如果上面的代码不起作用,请升级到最新的 Java 8 补丁版本。

    编辑:只是补充一点,Instant 是您想要在没有任何其他上下文的情况下及时存储瞬间时使用的正确类。

    【讨论】:

      【解决方案2】:

      使用带有年份或其他字段的格式化程序格式化Instant 时出现的错误是预期的; Instant 不知道它是哪一年、哪一个月或哪一天,它只知道自 Epoch 以来经过了多少毫秒。对于同一时刻,可能是地球上 2 个不同地方的 2 个不同日子。

      因此,如果要打印日期,则需要添加时区信息。使用Instant,您可以调用atZone(zone) 将其与ZoneId 组合成ZonedDateTime。这很像一个瞬间,只是它有一个时区信息。如果要使用系统时区(正在运行的虚拟机之一),可以通过ZoneId.systemDefault() 获取。

      要打印它,您可以使用两个内置格式化程序ISO_OFFSET_DATE_TIMEISO_ZONED_DATE_TIME。两者的区别在于分区日期时间格式化程序会将区域 id 添加到输出中。

      Instant instant = Instant.now();
      DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
      System.out.println(formatter.format(instant.atZone(ZoneId.systemDefault())));
      System.out.println(formatter.format(instant.atZone(ZoneId.of("America/Los_Angeles"))));
      

      在我的机器上运行时,系统时区为"Europe/Paris",你会得到:

      2016-07-31T18:58:54.108+02:00
      2016-07-31T09:58:54.108-07:00
      

      如果这些格式不适合您,您当然可以使用ofPattern 或构建器DateTimeFormatterBuilder 构建自己的格式化程序。

      【讨论】:

        【解决方案3】:

        我同意这有点令人困惑,尤其是与它的前身 Joda DateTime 相比时。

        最令人困惑的是,LocalDateTime 的文档说它是“没有时区的日期时间”,然而 LocalDateTime.ofInstant 方法将即时和时区作为参数。

        也就是说,我认为您可以通过使用 UTC 时区使用 Instant 和 LocalDateTime.ofInstant 来实现您想要的。

        public LocalDateTime millisToDateTime(long millis) {
          return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of("Z");
        } 
        

        【讨论】:

          猜你喜欢
          • 2015-08-19
          • 2018-06-15
          • 1970-01-01
          • 2020-03-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-03-23
          • 2020-06-22
          相关资源
          最近更新 更多