Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 - DateTimeFormatter and ISO_INSTANT issues with ZonedDateTime

So I would expect this code to work under the new Java 8 date/time package since all it does is to convert a given ZonedDateTime to string and back using the same built-in DateTimeFormatter instance (ISO_INSTANT):

ZonedDateTime now = ZonedDateTime.now(); System.out.println(ZonedDateTime.parse(     now.format(DateTimeFormatter.ISO_INSTANT),     DateTimeFormatter.ISO_INSTANT)); 

But apparently it doesn't:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2014-09-01T19:37:48.549Z' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {MilliOfSecond=549, NanoOfSecond=549000000, MicroOfSecond=549000, InstantSeconds=1409600268},ISO of type java.time.format.Parsed     at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1918)     at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1853)     at java.time.ZonedDateTime.parse(ZonedDateTime.java:597) 

I have seen this entry already, but it didn't help me because a need a ZonedDateTime object and not a local one and also because I already have 8u20 installed: Unable to obtain ZonedDateTime from TemporalAccessor using DateTimeFormatter and ZonedDateTime in Java 8

Anyone have any idea what's happening here?

like image 458
asieira Avatar asked Sep 01 '14 19:09

asieira


People also ask

Is DateTimeFormatter thread-safe Java?

Yes, it is: DateTimeFormat is thread-safe and immutable, and the formatters it returns are as well. Implementation Requirements: This class is immutable and thread-safe.

What is iso_instant?

The ISO_INSTANT formatter is a special case formatter designed to work with Instant . If you are using a ZonedDateTime you should use a different formatter, such as ISO_DATE_TIME or ISO_ZONED_DATE_TIME .

How do I use DateTimeFormatter with date?

DateTimeFormatter fmt = DateTimeFormatter. ofPattern("yyyy-MM-dd'T'HH:mm:ss"); System. out. println(ldt.

What is ZonedDateTime format?

ZonedDateTime is an immutable representation of a date-time with a time-zone. This class stores all date and time fields, to a precision of nanoseconds, and a time-zone, with a zone offset used to handle ambiguous local date-times.


2 Answers

The ISO_INSTANT formatter is documented here - "This is a special case formatter intended to allow a human readable form of an Instant". As such, this formatter is intended for use with an Instant not a ZonedDateTime.

Formatting

When formatting, ISO_INSTANT can format any temporal object that can provide ChronoField.INSTANT_SECONDS and ChronoField.NANO_OF_SECOND. Both Instant and ZonedDateTime can provide these two fields, thus both work:

// works with Instant Instant instant = Instant.now(); System.out.println(DateTimeFormatter.ISO_INSTANT.format(instant));  // works with ZonedDateTime  ZonedDateTime zdt = ZonedDateTime.now(); System.out.println(zdt.format(DateTimeFormatter.ISO_INSTANT));  // example output 2014-09-02T08:05:23.653Z 

Parsing

When parsing, ISO_INSTANT will only produce ChronoField.INSTANT_SECONDS and ChronoField.NANO_OF_SECOND. An Instant can be built from those two fields, but ZonedDateTime requires a ZoneId as well:

To parse a ZonedDateTime it is essential that a time-zone ZoneId is present. The time-zone can be (a) parsed from the string, or (b) specified to the formatter (using JDK 8u20):

// option a - parsed from the string DateTimeFormatter f = DateTimeFormatter.ISO_DATE_TIME; ZonedDateTime zdt = ZonedDateTime.parse("2014-09-02T08:05:23.653Z", f);  // option b - specified in the formatter - REQUIRES JDK 8u20 !!! DateTimeFormatter f = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.systemDefault()); ZonedDateTime zdt = ZonedDateTime.parse("2014-09-02T08:05:23.653Z", f); 

See documentation for ISO_ZONED_DATE_TIME, ISO_OFFSET_DATE_TIME and ISO_DATE_TIME (any of these three can be used to parse a ZonedDateTime without specifying withZone()).

Summary

The ISO_INSTANT formatter is a special case formatter designed to work with Instant. If you are using a ZonedDateTime you should use a different formatter, such as ISO_DATE_TIME or ISO_ZONED_DATE_TIME.

like image 158
JodaStephen Avatar answered Oct 08 '22 23:10

JodaStephen


I'm not sure, but this might be a bug in Java 8. Maybe it was intended to behave in this way, but I think that the workaround I'm going to propose to you should be the default behavior (when no ZoneId is specified, just take system default):

ZonedDateTime now = ZonedDateTime.now(); DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT     .withZone(ZoneId.systemDefault()); System.out     .println(ZonedDateTime.parse(now.format(formatter), formatter)); 

There's a similar bug which was fixed in OpenJDK: JDK-8033662 - but it's only similar, not exactly the same.

like image 42
Cristina_eGold Avatar answered Oct 08 '22 21:10

Cristina_eGold