Java 8个epoch-millis时间戳到格式化日期,如何?
Java 8 epoch-millis time stamp to formatted date, how?
在 Java-8 之前,我习惯于始终将任何 date/time 相关的内容保持为自 Epoch 以来的毫秒数,并且只在出路时处理人类可读的 dates/times,即在一个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 时间戳格式化为带时区的 date/time?
我同意这有点令人困惑,尤其是与它的前身 Joda DateTime 相比时。
最令人困惑的是,LocalDateTime 的文档说它是 "A date-time without a time-zone",而 LocalDateTime.ofInstant 方法同时将时间和时区作为参数。
也就是说,我认为您可以通过使用 Instant 和 LocalDateTime.ofInstant 通过使用 UTC 时区来实现您想要的。
public LocalDateTime millisToDateTime(long millis) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of("Z");
}
使用以年份或其他字段构建的格式化程序格式化 Instant
时出现的错误是预期的;一个 Instant
不知道现在是哪一年或哪月或哪天,它只知道自 Epoch 以来已经过去了多少毫秒。对于同一瞬间,它可能是地球上 2 个不同地方的 2 个不同的日子。
所以如果要打印日期,需要添加时区信息。使用 Instant
,您可以调用 atZone(zone)
to combine it with a ZoneId
in order to form a ZonedDateTime
. This is very much like an instant, only that it has a time zone information. If you want to use the system time zone (the one of the running VM), you can get it with ZoneId.systemDefault()
.
要打印它,您可以使用两个内置的格式化程序ISO_OFFSET_DATE_TIME
or ISO_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
or the builder DateTimeFormatterBuilder
。
Instant
不包含任何时区信息,与其他地方不同,不会自动使用默认时区。因此,格式化程序无法确定年份,因此会出现错误消息。
因此,要格式化即时,您必须添加时区。这可以使用 withZone(ZoneId)
直接添加到格式化程序中 - 无需手动转换为 ZonedDateTime
*:
ZoneId zone = ZoneId.systemDefault();
DateTimeFormatter df = DateTimeFormatter.ofPattern("...pattern...").withZone(zone);
df.format(Instant.ofEpochMilli(timestamp))
* 遗憾的是,在早期的Java8版本中,DateTimeformatter.withZone(ZoneId)
方法并没有起作用,但是现在已经修复了,所以如果上面的代码不起作用,请升级到最新的Java 8 个补丁发布。
编辑:只是补充说 Instant
是正确的 class,当您想在没有任何其他上下文的情况下及时存储瞬间时使用。
在 Java-8 之前,我习惯于始终将任何 date/time 相关的内容保持为自 Epoch 以来的毫秒数,并且只在出路时处理人类可读的 dates/times,即在一个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 时间戳格式化为带时区的 date/time?
我同意这有点令人困惑,尤其是与它的前身 Joda DateTime 相比时。
最令人困惑的是,LocalDateTime 的文档说它是 "A date-time without a time-zone",而 LocalDateTime.ofInstant 方法同时将时间和时区作为参数。
也就是说,我认为您可以通过使用 Instant 和 LocalDateTime.ofInstant 通过使用 UTC 时区来实现您想要的。
public LocalDateTime millisToDateTime(long millis) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of("Z");
}
使用以年份或其他字段构建的格式化程序格式化 Instant
时出现的错误是预期的;一个 Instant
不知道现在是哪一年或哪月或哪天,它只知道自 Epoch 以来已经过去了多少毫秒。对于同一瞬间,它可能是地球上 2 个不同地方的 2 个不同的日子。
所以如果要打印日期,需要添加时区信息。使用 Instant
,您可以调用 atZone(zone)
to combine it with a ZoneId
in order to form a ZonedDateTime
. This is very much like an instant, only that it has a time zone information. If you want to use the system time zone (the one of the running VM), you can get it with ZoneId.systemDefault()
.
要打印它,您可以使用两个内置的格式化程序ISO_OFFSET_DATE_TIME
or ISO_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
or the builder DateTimeFormatterBuilder
。
Instant
不包含任何时区信息,与其他地方不同,不会自动使用默认时区。因此,格式化程序无法确定年份,因此会出现错误消息。
因此,要格式化即时,您必须添加时区。这可以使用 withZone(ZoneId)
直接添加到格式化程序中 - 无需手动转换为 ZonedDateTime
*:
ZoneId zone = ZoneId.systemDefault();
DateTimeFormatter df = DateTimeFormatter.ofPattern("...pattern...").withZone(zone);
df.format(Instant.ofEpochMilli(timestamp))
* 遗憾的是,在早期的Java8版本中,DateTimeformatter.withZone(ZoneId)
方法并没有起作用,但是现在已经修复了,所以如果上面的代码不起作用,请升级到最新的Java 8 个补丁发布。
编辑:只是补充说 Instant
是正确的 class,当您想在没有任何其他上下文的情况下及时存储瞬间时使用。