Jackson deserialize ISO8601 formatted date-time into Java8 Instant

I'm trying to deserialize an ISO8601 formatted date into Java8 java.time.Instant using Jackson. I registered JavaTimeModule with the ObjectMapper, and turned off the WRITE_DATES_AS_TIMESTAMPS setting.

However, if one tries to deserialize 2016-03-28T19:00:00.000+01:00 it will not work, because it seems that JavaTimeModule will only deserialize date-times formatted with UTC timezone offset (e.g. 2016-03-28T18:00:00.000Z). I then tried using @JsonFormat annotation like this:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "UTC")

And like this:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = JsonFormat.DEFAULT_TIMEZONE)

However, neither of these work and I get an exception:

com.fasterxml.jackson.databind.JsonMappingException: Unsupported field: YearOfEra (through reference chain: org.example.Article["date"])

Which implies that timezone parameter is ignored and date time formatter doesn't know how to format an Instant without a timezone.

Is there a way to deserialize a ISO8601 string that's not in UTC time zone offset to Java 8 java.time.Instant using Jackson and JavaTimeModule without writing a custom deserializer?


You need to set the explicit time zone via XXX in your modell class:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")

(see: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html)


If you want to serialize Date objects into ISO-8601, you don't need to specify a pattern at all - ISO-8601 is the default pattern. It is kind of mentioned in the JsonFormat Java doc:

Common uses include choosing between alternate representations -- for example, whether Date is to be serialized as number (Java timestamp) or String (such as ISO-8601 compatible time value) -- as well as configuring exact details with pattern() property.

[emphasasis mine] you should understand from the above text that specifying shape = STRING would mean an ISO-8601 format but you can choose something else using the pattern property.

In my experience, this always turns out a UTC date format (with the time zone rendered as +0000), which could be the default time zone in my VM (even though my operating system clock is not set to UTC).


In Jackson 2.9.8 (current one as I'm writing this) it's better to use Instant instead of Date.

You have to add a dependency:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.9.8</version>
</dependency> 

Also, register the module and configure SerializationFeature.WRITE_DATES_AS_TIMESTAMPS to false.

new ObjectMapper()
                .findAndRegisterModules()
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

More information about Jackson for Java8 here: https://github.com/FasterXML/jackson-modules-java8


The format "Z" does not work with "+01:00" as this is a different pattern. JsonFormat is using SimpleDateFormat patterns. "Z" in upper case only represents strict RFC 822. You have to use syntax like: "+0100", without colon.

See: ISO 8601:2004, SimpleDateFormat patterns


Jackson can be configured globally (without annotations) to accept timestamps with or without colon:

ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new StdDateFormat().withColonInTimeZone(true));

The default Jackson timezone format was changed since version 2.11 from '+0000' to '+00:00'. Both formats are valid according to ISO-8601.