8

I am having some issue with date logic which I've isolated to Jackson, the JSON serializer.

In the database and in a debug point in the application, dates are correct and everything is written using default timezone. However, in serialization 4 hours are being added. I found this could be remedied by telling Jackson specifically to use EST (it was defaulting to UTC). As below:

@JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss.SSSZ", timezone="America/New_York")
private Date startDate;

However, the problem is that only local is using EST and the server will be using UTC. I need Jackson to use system defaults.

Luckily, I found this similar question which is backed up by the documentation. New solution:

@JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss.SSSZ", timezone=JsonFormat.DEFAULT_TIMEZONE)
private Date startDate;

However, it doesn't work! I tried also timezone='DEFAULT_TIMEZONE' and a variety of other things but in all cases the api output still seems to be 4 hours ahead of the number in the database.

Other things I have tried:

  • logging out JsonFormat.DEFAULT_TIMEZONE returns ##default.
  • logging TimeZone.getDefault().getDisplayName() returns Eastern Standard Time.

Jackson version is 2.9.

Any suggestions?

8t12c7081
  • 683
  • 3
  • 9
  • 30
  • I suggest having a look at this other question [Whats wrong with java date & time api](https://stackoverflow.com/questions/1969442/whats-wrong-with-java-date-time-api) – Lino Mar 18 '19 at 15:11
  • Hi Lino - this was a fun read but not relevant to my issue, which occurs specifically in serialization. I've used a debugger in the endpoint to verify there is no issue with the date logic on the back-end. The 4 hrs are added specifically in serialization. – 8t12c7081 Mar 18 '19 at 15:16

1 Answers1

12

Solved my own question. Here is what I found:

JsonFormat.DEFAULT_TIMEZONE is NOT the system default, as the documentation and SO answer suggest, but actually defaults to UTC.

org.springframework.http.converter.json.Jackson2ObjectMapperBuilder

/**
 * Override the default {@link TimeZone} to use for formatting.
 * Default value used is UTC (NOT local timezone).
 * @since 4.1.5
 */
public Jackson2ObjectMapperBuilder timeZone(TimeZone timeZone) {

com.fasterxml.jackson.annotation.JsonFormat

/**
 * Value that indicates that default {@link java.util.TimeZone}
 * (from deserialization or serialization context) should be used:
 * annotation does not define value to use.
 *<p>
 * NOTE: default here does NOT mean JVM defaults but Jackson databindings
 * default, usually UTC, but may be changed on <code>ObjectMapper</code>.
 */
public final static String DEFAULT_TIMEZONE = "##default";

Solution:

@Autowired
com.fasterxml.jackson.databind.ObjectMapper objectMapper;

and objectMapper.setTimeZone(TimeZone.getDefault()) in a config class, like so:

package path.to.config;
import ...

@Configuration
public class JacksonConfiguration {

    @Autowired
    public JacksonConfiguration(ObjectMapper objectMapper){
        objectMapper.setTimeZone(TimeZone.getDefault());
    }
}

This should set the Jackson ObjectMapper to use system default instead of Jackson default (UTC).

8t12c7081
  • 683
  • 3
  • 9
  • 30
  • Hi @VKing34, in this case I put the Autowired objectMapper at the top of my class (injecting the objectMapper for use in the class) and the .setTimeZone should be on the same object - so either below the injection in the same class (but before your objectmapper is used) OR in some sort of global configuration class (the more proper solution) – 8t12c7081 Dec 09 '20 at 02:18
  • objectMapper.setTimeZone(TimeZone.getDefault()); where do we write this piece of code because values will already be deserialized if we put this inside the method accepting the request body? – unknown May 15 '21 at 06:03
  • @unknown I used a config class - added that code above – 8t12c7081 May 16 '21 at 18:11