76

I'm getting a date string from ExtJS in the format:

"2011-04-08T09:00:00"

when i try to deserialize this date, it changes the timezone to Indian Standard Time (adds +5:30 to the time) . This is how i'm deserializing the date:

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
getObjectMapper().getDeserializationConfig().setDateFormat(dateFormat);

Doing this also doesn't change the timezone. I still get the date in IST:

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
getObjectMapper().getDeserializationConfig().setDateFormat(dateFormat);

How do I deserialize the date in the way in which it is coming without the hassles of Timezone?

Rubens Mariuzzo
  • 28,358
  • 27
  • 121
  • 148
Varun Achar
  • 14,781
  • 7
  • 57
  • 74

5 Answers5

147

I found a work around but with this I'll need to annotate each date's setter throughout the project. Is there a way in which I can specify the format while creating the ObjectMapper?

Here's what I did:

public class CustomJsonDateDeserializer extends JsonDeserializer<Date>
{
    @Override
    public Date deserialize(JsonParser jsonParser,
            DeserializationContext deserializationContext) throws IOException, JsonProcessingException {

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        String date = jsonParser.getText();
        try {
            return format.parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

    }

}

And annotated each Date field's setter method with this:

@JsonDeserialize(using = CustomJsonDateDeserializer.class)
Varun Achar
  • 14,781
  • 7
  • 57
  • 74
  • 1
    What's the 'T' in the format for, shouldn't it be "yyyy-MM-dd HH:mm:ss" – Bryan Hunt Jun 16 '12 at 10:17
  • It's a valid date time pattern. For example even `yyyy.MM.dd G 'at' HH:mm:ss z` and `hh 'o''clock' a, zzzz` are valid patterns. – Varun Achar Jun 26 '12 at 17:23
  • Didn't work for me (Linux sun 1.7), removing the 'T' works (in my use case) – Bryan Hunt Jun 26 '12 at 18:17
  • Yes. The format posted is the default used by JDK on my machine. The format is just a sample. You can change it according to your use case. :) – Varun Achar Jun 27 '12 at 03:44
  • T should be there: http://jackson.codehaus.org/1.1.2/javadoc/org/codehaus/jackson/map/util/StdDateFormat.html – Blessed Geek Jun 27 '12 at 18:17
  • 10
    The 'T' is in the format because this is using the ISO 8601 Standard of date time formatting. You obviously are not required to use an ISO standard format, but it can help with compatibility when using 3rd party libraries such as ExtJS. http://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations – Patrick Sep 07 '12 at 14:51
  • Note that, at least on in my implementation of a similar solution on Jackson 2.1.2, the CustomJsonDateDeserializer needs to be static, or you'll get NPEs when you try and parse. – jjb Dec 19 '12 at 05:49
  • 9
    @jjb NO, this is really wrong. As simpleDateFormatter are not thread safe, and as jackons caches root level Deserializers (and this can't be disabled), you MUST either use a different SimpleDateFormatter for each date as proposde by Varun Achar or synchronize the deserialize method is you use a field for the SimpleDateFormatter. And this field can't be static. This was one of the nastyest bug I ever saw. – Snicolas Jun 19 '13 at 15:26
  • @Snicolas In my case, the deserializer was an inner class, and it needs to be static since Jackson doesn't have an instance of the outer class. It's not a static field of anything. – jjb Jun 26 '13 at 18:26
  • @VarunAchar Do you understand why the `CustomJsonDateDeserializer` would not be used if you specify the `as = Date.class` attribute as specified in the [documentation](http://fasterxml.github.io/jackson-databind/javadoc/2.4/com/fasterxml/jackson/databind/annotation/JsonDeserialize.html)? I could only get it running when I use `using =` but no other attribute. – JJD Nov 07 '14 at 20:56
  • Thanks Varun for your post. I got a clue through your solution. – sayan Dec 17 '14 at 12:44
  • 1
    This was helpful, thanks a lot. Since I'm using Java 8 I posted an answer using LocalDate, see http://stackoverflow.com/a/31810856/60518. – Tim Büthe Aug 04 '15 at 13:39
  • Also works with @JSonSerialize when you need to do serialization instead of deserialization. – obesechicken13 Jan 20 '16 at 22:50
  • Exactly what I needed, great job. Any chance to have this decoder as a bean (to make sure autowired beans get injected)? – Sergei Ledvanov Aug 18 '17 at 06:44
59

This works for me - i am using jackson 2.0.4

ObjectMapper objectMapper = new ObjectMapper();
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
objectMapper.setDateFormat(df);
Himanshu
  • 31,810
  • 31
  • 111
  • 133
Balaji Natesan
  • 791
  • 6
  • 4
  • 10
    Or instead of SimpleDateFormat, I use new ISO8601DateFormat(), which is inline with most other language's defaults (C#, Ruby, etc) – Christopher Davies Sep 13 '12 at 04:16
  • Your answer is simpler than the above answers, and it also covers both serializing AND de-serializing in one line. Great! – jasop Dec 26 '12 at 05:44
  • 3
    Is setDateFormat deprecated? – Albert Cheng Mar 21 '13 at 00:49
  • 3
    I am new to jackson, I am wondering where to add the above code? – Harbir Jul 15 '14 at 01:07
  • 2
    'objectMapper.setDateFormat(df);' is good if you only have an utility or a unique bean in which you set the format, otherwise you always have to remember to set it wherever you use it. Also, DateFormat is not thread safe! – Giuseppe Adaldo Nov 17 '14 at 11:49
  • 1
    `ObjectMapper` is thread safe. You only need one instance of it for for each configuration, i.e., if you need 2 different date formats, then you need 2 `ObjectMapper` objects, or only one but you need to `synchronize` the call to the `setDateFormat` method. – Varun Achar Nov 27 '14 at 05:19
  • @Balaji-Natesan seriously where does this code *go*? I see references to an explicit objectMapper in lots of Jackson docs but never see how to wire that to the actual business of deserializing things (via annotations, generally). – a p May 11 '16 at 22:23
  • @Harbir create a class with the annotation `@Configuration`, that extends `WebMvcConfigurerAdapter` and override the method `configureMessageConverters`. – Dherik Dec 06 '17 at 16:35
14

There is a good blog about this topic: http://www.baeldung.com/jackson-serialize-dates Use @JsonFormat looks the most simple way.

public class Event {
    public String name;

    @JsonFormat
      (shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
    public Date eventDate;
}
Alykoff Gali
  • 1,121
  • 17
  • 32
wangf
  • 895
  • 9
  • 12
6

In addition to Varun Achar's answer, this is the Java 8 variant I came up with, that uses java.time.LocalDate and ZonedDateTime instead of the old java.util.Date classes.

public class LocalDateDeserializer extends JsonDeserializer<LocalDate> {

    @Override
    public LocalDate deserialize(JsonParser jsonparser, DeserializationContext deserializationcontext) throws IOException {

        String string = jsonparser.getText();

        if(string.length() > 20) {
            ZonedDateTime zonedDateTime = ZonedDateTime.parse(string);
            return zonedDateTime.toLocalDate();
        }

        return LocalDate.parse(string);
    }
  }
Community
  • 1
  • 1
Tim Büthe
  • 62,884
  • 17
  • 92
  • 129
  • 3
    You might be able to configure and use Jackson's [JSR-310 datatype module](https://github.com/FasterXML/jackson-datatype-jsr310) instead of writing your own deserializer. – Paul Nov 04 '15 at 17:51
-2

@JsonFormat only work for standard format supported by the jackson version that you are using.

Ex :- compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd")) for jackson 2.8.6