Java 8 epoch-millis时间戳到格式化日期,怎么样?

时间:2016-07-31 13:53:16

标签: java datetime java-8 java-time

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

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

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

但它在我Unsupported field: YearOfEra Instant.getLong(...)中的Instant突然爆炸,我不明白。现在使用什么而不是LocalDateTime.ofEpoch(Instant, ZoneId)

Instant似乎错了,因为我不在乎当地的时间。我只是想在应用格式化程序时看到本地时区。在内部,它应该只是ZonedDateTime.ofInstant(Instant, ZoneId)

同样适用于ZoneId,我认为仅在格式化时应用DateTimeFormatter。但我注意到<paper-toolbar> <span class="title">Sample!</span> <paper-icon-button icon="[[statusIcon(signedIn)]]" on-tap="processAuth"> </paper-icon-button> </paper-toolbar> <firebase-auth id="auth" app-name="emotions" provider="google" signed-in="{{signedIn}}" user="{{user}}"> </firebase-auth> 本身不再与时区有关,似乎,所以我认为我需要使用上述之一。

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

3 个答案:

答案 0 :(得分:9)

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是您想要在没有任何其他背景的情况下及时存储的正确类。

答案 1 :(得分:7)

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

因此,如果您想要打印当天,则需要添加时区信息。使用Instant,您可以致电atZone(zone)将其与ZoneId合并,以形成ZonedDateTime。这非常像一个瞬间,只有它有一个时区信息。如果要使用系统时区(正在运行的VM之一),可以使用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构建自己的格式化程序。

答案 2 :(得分:1)

我同意这有点令人困惑,特别是与它的前任Joda DateTime相比时。

最令人困惑的是,LocalDateTime的文档说它是&#34;没有时区&#34;的日期时间,而LocalDateTime.ofInstant方法同时采用即时和时区作为参数。

那就是说,我认为你可以通过使用UTC时区使用Instant和LocalDateTime.ofInstant来达到你想要的效果。

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