3

With Spring MVC (Spring boot) I can deserialize ZonedDateTime from

2016-07-26T05:30:47+01:00

but not from

2016-07-26T05:30:47+01:00 Europe/Paris

How can I explicitly add timezone and still be able to deserialize it?

piotrek
  • 13,982
  • 13
  • 79
  • 165
  • The term "Europe/Paris" denotes a full timezone including any transition history, actual and future daylight saving rules AND the version of the underlying timezone data. So serializing and deserializing would potentially require to transfer all this stuff, not only the string "Europe/Paris". In my opinion, it is not a good idea to serialize all. Have you considered to only serialize the instant of `ZonedDateTime` ensuring better performance? – Meno Hochschild Jul 30 '16 at 06:34

1 Answers1

6

You can specify a pattern with an optional section (delimited by []), to indicate that some field is optional, and add this to the respective field using the @JsonFormat annotation.

For example, take this class:

public class OptionalTimeZoneTest {

    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX[ VV]")
    private ZonedDateTime date;

    // getter and setter
}

Note the last part ([ VV]): the pattern inside [] is an optional section, so the parser tries to parse it, if present. And the pattern VV is the zone id (or timezone's name; for more details, take a look at the javadoc)

With this, both formats can be read:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
// add this to preserve the same offset (don't convert to UTC)
mapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);

// without timezone
String json = "{ \"date\": \"2016-07-26T05:30:47+01:00\" }";
OptionalTimeZoneTest value = mapper.readValue(json, OptionalTimeZoneTest.class);
System.out.println(value.getDate()); // 2016-07-26T05:30:47+01:00

// with timezone
json = "{ \"date\": \"2016-07-26T05:30:47+01:00 Europe/Paris\" }";
value = mapper.readValue(json, OptionalTimeZoneTest.class);
System.out.println(value.getDate()); // 2016-07-26T05:30:47+02:00[Europe/Paris]

The output is:

2016-07-26T05:30:47+01:00
2016-07-26T05:30:47+02:00[Europe/Paris]

Note that in the first case the output is 2016-07-26T05:30:47+01:00 (because it doesn't have a timezone, so the +01:00 offset is applied).

But in the second case the output is 2016-07-26T05:30:47+02:00[Europe/Paris], because in Europe/Paris timezone, 26/07/2016 is summer-time (so the offset is +02:00). And the java.time API were implemented in a way that the timezone takes precedence when parsing such a String.


If you want all ZonedDateTime instances to be converted to UTC, you can remove this line:

mapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);

Without it, the dates will be converted to UTC, and the output will be:

2016-07-26T04:30:47Z[UTC]
2016-07-26T03:30:47Z[UTC]