Harald Harald - 4 months ago 17
Java Question

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

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?

Answer

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.

Comments