Jackson-databind: Jackson adjusts date even though date format doesn't contain timezone

Created on 27 Feb 2018  路  11Comments  路  Source: FasterXML/jackson-databind

For some reason jackson adjusts the date, even though the date format doesn't contain the timezone.
E.g.
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")

Binds a string of "2018-02-15T11:43:00" to a Date of "2018-02-15 12:43:00" on my local system.
Shouldn't jackson be neutral on the timezone if it is not explicitly provided?
Is it possible to configure the current version of jackson to follow the expected behavior (Date of "2018-02-15 11:43:00" in above case)

Most helpful comment

Just for people who are searching the same issue and have reached this ticket, if your date is such like a birthday, and you don't care about the timezone and timestamp at all, you'd better use LocalDateTime or LocalDate instead of Date.

All 11 comments

@kst83 Please note that java.util.Date does not contain any timezone information: it is a timestamp, and its interpretation unfortunately depends on some external information.

Aside from that, description of the issue alone is not sufficient: what is needed is a reproduction to show in code your problem.

The code is part of a big project and also uses Spring Integration, so I can't just post it as an example.
All I want is getting the exact same date as in the json string, ignoring any timezone information.
Is this really not possible with jackson?

I've seen some testing examples, so I've written a few lines in that style:

        ObjectMapper mapper = new ObjectMapper();
        Date date = mapper.readValue("\"1970-01-01T00:00:00.000\"", java.util.Date.class);

The resulting date is 1970-01-01 01:00:00 on my system, I expected it to be 1970-01-01 00:00:00.

EDIT: I've figured out a workaround, though it is not very nice:

        ObjectMapper mapper = new ObjectMapper();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        df.setTimeZone(TimeZone.getDefault());
        mapper.setDateFormat(df);
        Date date = mapper.readValue("\"1970-01-01T00:00:00.000\"", java.util.Date.class);

Since I'm using this in spring integration 4.x it requires me to create a modified copy of Jackson2JsonObjectMapper that sets the date format.
Also the workaround breaks if the date pattern is set using annotations:

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

Is there any better way of solving this issue?

@kst83 I am not sure you quite understand my comment: value of java.util.Date literally do not have timezone information -- they do not "know" timezone you might want to use. There is absolutely nothing retained even if incoming String did have timezone: this timezone is used for calculations but then dropped. If you want to retain it, you are better off with Joda or Java 8 date/time values which do retain this information.

As to configuration, yes, those are the ways to force use of specific timezone for serialization.
There is third way via ObjectMapper.configOverrides(Date.class).setFormat(....), which allows assigning specific formats for all instances of Date. But I am guessing you do want it applied to all types anyway.

I don't want to retain timezone information. I just want the deserialized Date to have exactly the same values as the string, completely ignoring the timezone problem.
Can configOverrides be used for deserializion too? Or is it just for serialization?

@kst83 That is the exact same value: value is 64-bit long, see getTime() method and verify values.

Date does not have specific String representation any more than timezone assignment. One can write textual representation, with formatting and timezone.

At this point I think you really need to learn more about Java Date handling -- I have given pointers that should help.

Somehow I get the feeling we are talking about different things.

I'm doing the following:

I execute the code above (cited here again):

        ObjectMapper mapper = new ObjectMapper();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        df.setTimeZone(TimeZone.getDefault());
        mapper.setDateFormat(df);
        Date date = mapper.readValue("\"1970-01-01T00:00:00.000\"", java.util.Date.class);

Then I pause for debugging and point the mouse over the variable "date" to show the mouse over hint of its values. It shows that the hour of the date is set to 01 instead of the 00 written in the code.
Is this really the intended behaviour?

@kst83 I don't think you are listening. java.util.Date does not have concept of hours, minutes or any other components. It is a wrapper around 64-bit values. Your IDE may choose to construct a Calendar from it to try to be helpful. That does not mean they exist as distinct values without necessary information: specific timepoint IN WHICH TIMEZONE (or, formatted how? Date does not have formatting either).

There are many cases where just printing out strings (or looking at Strings your tools show you) does not help unless you are understand what transformations are being done for you, and I find it frustrating to talk when you seem unwilling to learn about these aspects.

Sorry, I didn't understand that. I thought the IDE shows the internal structure of the data.
So basically even if I write a unit test that compares the deserialized Date with a Date generated by the applying the SimpleDateFormat parse function to the same String, it might be ok if they don't match up.
Guess I'll really have to look up more documentation on this topic.

@kst83 Right. Date itself only contains very specific timepoint. Calendar then contains parts -- or, even better, Java 8 and Joda libraries that contains "zoned" date/time values that have this information. Name Date is pretty misleading.

Just for people who are searching the same issue and have reached this ticket, if your date is such like a birthday, and you don't care about the timezone and timestamp at all, you'd better use LocalDateTime or LocalDate instead of Date.

Was this page helpful?
0 / 5 - 0 ratings