31

I have been used Spring Date Rest with Spring Boot in my project. This project has a object and I have used the annotation @JsonFormat to format the date field that will be received from my Json. The format of field Date is "dd/MM/yyyy". When I send in my json the value "08/07/1980" the Jackson convert to the value "07/07/1980".

The problem is that @JsonFormat set the date with one day less

This is my source code

@Temporal(TemporalType.DATE)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy", locale = "pt-BR", timezone = "UTC")
private Date birthDate;

Thanks

William Miranda
  • 493
  • 1
  • 7
  • 13
  • 1
    I guess you mean when performing a request to your backend. Is the client a browser or some sort of REST tool? Are both client and server in the same time zone? – franDayz Aug 05 '15 at 07:05
  • 1
    My first guess is that since you are using UTC and omitting hours and seconds, the offset between Brazil and UTC is being applied causing loss of time information. As a quick try you can omit the locale property from the annotation and use this pattern instead "yyyy-MM-dd'T'HH:mm:ss.SSSZ" which includes timezone information and miliseconds so it does not matter the representation the client chooses – franDayz Aug 05 '15 at 07:16

5 Answers5

41

Use this solution, it is more effective and modern than my solution: https://stackoverflow.com/a/45456037/4886918

Thanks @Benjamin Lucidarme.

I resolved my problem using:

@Temporal(TemporalType.DATE)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy", locale = "pt-BR", timezone = "Brazil/East")
private Date birthDate;

I changed timezone to "Brazil/East" or "America/Sao_Paulo" and working now

Thanks

peterh
  • 11,875
  • 18
  • 85
  • 108
19

@William's answer works but you should add theses lines to your application.properties files instead:

spring.jackson.time-zone=Brazil/East
spring.jackson.locale=pt-BR

In that way, you indicate the time-zone and locale only one time, and it applicate to all the Date of your application.

Benjamin Lucidarme
  • 1,648
  • 1
  • 23
  • 39
5

I'd go with setting ObjectMapper timezone as default JVM timezone:

    ObjectMapper objectMapper = new ObjectMapper();
    //Set default time zone as JVM timezone due to one day difference between original date and formatted date.
    objectMapper.setTimeZone(TimeZone.getDefault());

It's a better solution if you don't know what timezone is used on a server environment.

In spring-boot environment you can override default JacksonAutoConfiguration:

@Bean
ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
    return builder.createXmlMapper(false)
            // Set timezone for JSON serialization as system timezone
            .timeZone(TimeZone.getDefault())
            .build();
}
Michał Stochmal
  • 5,895
  • 4
  • 36
  • 44
3

On both side (Client - Server) annotate your date filed like this:

@JsonDeserialize(using = JsonDateDeserializer.class)
@JsonSerialize(using = JsonDateSerializer.class)
private Date birthDate;

and on both side again put this implementations for serializing and deserializing:

public class JsonDateSerializer extends JsonSerializer<Date> {
    SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");

    @Override
    public void serialize(final Date date, final JsonGenerator gen, final SerializerProvider provider) throws IOException, JsonProcessingException {

        String dateString = format.format(date);
        gen.writeString(dateString);
    }

}


public class JsonDateDeserializer extends JsonDeserializer<Date> {

    SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");

    @Override
    public Date deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
        if (jp.getCurrentToken().equals(JsonToken.VALUE_STRING)) {
            try {
                Date date = format.parse(jp.getText().toString());
                return date;
            } catch (ParseException e) {
                //e.printStackTrace();
            }
        }
        return null;
    }

}
Mehdi
  • 3,795
  • 3
  • 36
  • 65
2

I too faced similar issue. I guess all the answers added for this question are specific to above question, my solution will explain the issue and provide generic solution.

You may face this issue, when you are using 2 different time-zones for same Date . When you do new Date(), it uses your default time-zone unless you explicitly specify time-zone. Lemme explain this to you with a code-snippet, (you are in India and current date is (9/5/2021, 12 a.m. IST)

// 09/05/2021 00:00:00 IST
Date birthDate = new Date();

Now, when set above birthDate to model and when it's serialized using JsonFormat. By default JsonFormat uses UTC time-zone.

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")
private Date birthDate;

Serialization will result in 08/05/2021, not 09/05/2021.
Lemme write the dates with timezone that's 08/05/2021 UTC, and 09/05/2021 IST.
Lemme add time too for dates, 08/05/2021 18:30:00 UTC, and 09/05/2021 00:00:00 IST.
Now you get why its happening, if you see dates are correct, but having different time-zones. There are 2 ways to handle this problem,

  1. Use same time-zones
  2. Add time and time-zones too while serializing dates. Like 08/05/2021 18:30:00 UTC, and 09/05/2021 00:00:00 IST
miPlodder
  • 795
  • 8
  • 18