Java 8 epoch-millis time stamp to formatted date, how?

时光毁灭记忆、已成空白 提交于 2020-12-29 10:14:40

问题


Before Java-8 I got accustomed to always keep anything date/time related as milliseconds since Epoch and only ever deal with human readable dates/times on the way out, i.e. in a UI or a log file, or when parsing user generated input.

I think this is still safe with Java-8, and now I am looking for the most concise way to get a formatted date out of a milliseconds time stamp. I tried

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

but it bombs out with Unsupported field: YearOfEra in Instant.getLong(...) which I half understand. Now what to use instead of Instant?

LocalDateTime.ofEpoch(Instant, ZoneId) seems wrong, since I don't care to have local time. I just want to see the local time zone when applying the formatter. Internally it should be just the Instant.

The same goes for ZonedDateTime.ofInstant(Instant, ZoneId), I thought to apply the ZoneId only when formatting. But I notice that the DateTimeFormatter does not itself deal anymore with time zones, it seems, so I reckon I need to use one of the above.

Which one is preferred and why? Or should I use yet another way to format an epoch-millis time stamp as a date/time with time zone?


回答1:


An Instant does not contain any information about the time-zone, and unlike in other places, the default time-zone is not automatically used. As such, the formatter cannot figure out what the year is, hence the error message.

Thus, to format the instant, you must add the time-zone. This can be directly added to the formatter using withZone(ZoneId) - there is no need to manually convert to ZonedDateTime *:

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

* regrettably, in early Java 8 versions, the DateTimeformatter.withZone(ZoneId) method did not work, however this has now been fixed, so if the code above doesn't work, upgrade to the latest Java 8 patch release.

Edit: Just to add that Instant is the right class to use when you want to store an instant in time without any other context.




回答2:


The error you have when formatting an Instant using a formatter built with a year or other fields is expected; an Instant does not know which year or month or day it is, it only knows how much milliseconds have elapsed since the Epoch. For the same instant, it could be 2 different days on 2 different places of the Earth.

So you need to add a time zone information if you want to print the day. With an Instant, you can call 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().

To print it, you can use the two built-in formatter ISO_OFFSET_DATE_TIME or ISO_ZONED_DATE_TIME. The difference between the two is that the zoned date time formatter will add the zone id to the output.

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"))));

when run on my machine, which has a system time zone of "Europe/Paris", you'll get:

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

You can of course build your own formatter if those one do not suit you, using ofPattern or the builder DateTimeFormatterBuilder.




回答3:


I agree that this is somewhat confusing, especially when compared with it's predecessor Joda DateTime.

The most confusing thing is that the documentation for LocalDateTime says that it is "A date-time without a time-zone", and yet LocalDateTime.ofInstant method takes both an instant and a timezone as parameters.

That said, I think that you can achieve what you want by using Instant and LocalDateTime.ofInstant by using the UTC timezone.

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


来源:https://stackoverflow.com/questions/38684650/java-8-epoch-millis-time-stamp-to-formatted-date-how

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!