Java 8 epoch-millis time stamp to formatted date, how?
Solution 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.
Solution 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
.
Solution 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");
}
Related videos on Youtube
Harald
formerly Enterprise Search Engineer now financial markets
Updated on September 15, 2022Comments
-
Harald over 1 year
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
inInstant.getLong(...)
which I half understand. Now what to use instead ofInstant
?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 theInstant
.The same goes for
ZonedDateTime.ofInstant(Instant, ZoneId)
, I thought to apply theZoneId
only when formatting. But I notice that theDateTimeFormatter
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?