Har*_*ald 8 java datetime java-8 java-time
在Java-8之前,我习惯于始终保持与Epoch相关的任何日期/时间相关的毫秒数,并且只能在出路时处理人类可读的日期/时间,即在UI或日志文件中,或在解析用户生成的输入时.
我认为这对Java-8来说仍然是安全的,现在我正在寻找一种最简洁的方法来获得一个毫秒时间戳的格式化日期.我试过了
df = Dateformatter.ofPattern("...pattern...");
df.format(Instant.ofEpochMilli(timestamp))
Run Code Online (Sandbox Code Playgroud)
但炸弹出与Unsupported field: YearOfEra在Instant.getLong(...)我一半懂.现在用什么而不是Instant?
LocalDateTime.ofEpoch(Instant, ZoneId)似乎错了,因为我不在乎当地的时间.我只是想在应用格式化程序时看到本地时区.在内部它应该只是Instant.
同样的ZonedDateTime.ofInstant(Instant, ZoneId),我想ZoneId只在格式化时应用.但是我注意到它DateTimeFormatter本身不再与时区有关,似乎,所以我认为我需要使用上述之一.
哪个是首选,为什么?或者我应该使用另一种方法将epoch-millis时间戳格式化为带时区的日期/时间?
An Instant不包含有关时区的任何信息,与其他地方不同,默认时区不会自动使用.因此,格式化程序无法确定年份是什么,因此错误消息.
因此,要格式化即时,您必须添加时区.这可以直接添加到格式化程序withZone(ZoneId)- 无需手动转换为ZonedDateTime*:
ZoneId zone = ZoneId.systemDefault();
DateTimeFormatter df = DateTimeFormatter.ofPattern("...pattern...").withZone(zone);
df.format(Instant.ofEpochMilli(timestamp))
Run Code Online (Sandbox Code Playgroud)
*遗憾的是,在早期的Java 8版本中,该DateTimeformatter.withZone(ZoneId)方法不起作用,但是现在已经修复了,所以如果上面的代码不起作用,请升级到最新的Java 8补丁版本.
编辑:只是要添加,这Instant是您想要在没有任何其他上下文的情况下及时存储的正确类.
Instant使用使用年份或其他字段构建的格式化程序格式化时出现的错误是预期的; 一个Instant不知道它是哪一年,一年或一个月或一天,它只知道自纪元以来已经过了多少毫秒.在同一时刻,它可能在地球的两个不同的地方有2个不同的日子.
因此,如果要打印当天,则需要添加时区信息.使用a Instant,您可以调用atZone(zone)它与a组合ZoneId以形成ZonedDateTime.这非常像一个瞬间,只有它有一个时区信息.如果要使用系统时区(正在运行的VM之一),则可以使用它ZoneId.systemDefault().
要打印它,您可以使用两个内置格式化程序ISO_OFFSET_DATE_TIME或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"))));
Run Code Online (Sandbox Code Playgroud)
当我的机器运行时,系统时区为"Europe/Paris",你会得到:
2016-07-31T18:58:54.108+02:00
2016-07-31T09:58:54.108-07:00
Run Code Online (Sandbox Code Playgroud)
如果那些格式化程序不适合您,使用ofPattern或构建器,您当然可以构建自己的格式化程序DateTimeFormatterBuilder.