Spring's @DateTimeFormat produces a Date object with the previous day
Asked Answered
L

4

11

I've got a requestParam that takes in a date (ie. 2017-01-24T06:00:00.000Z).

I'm using DateTimeFormat to format it into a date to pass into my controller.

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date myDate 

but when I print myDate to my console I get "Mon Jan 23, 18:00:00 CST 2017", but in my example above it should be Jan 24th. Why is it changing my date back 1 day?

Luddite answered 27/1, 2017 at 19:33 Comment(0)
C
16

There are several things at play here.

First, Spring's @DateTimeFormat, when annotating a java.util.Date field or parameter, uses a SimpleDateFormat with its timezone set to UTC.

Second, you've used DateTimeFormat.ISO.DATE which represents

The most common ISO Date Format yyyy-MM-dd, e.g. "2000-10-31".

In other words, it does not consider any timezone information in your date string (this doesn't really matter because your date string was rooted at Zulu anyway).

Third, you've provided a date string where everything but the iso pattern gets ignored. The SimpleDateFormat only cares about the 2017-01-24 part.

Since the timezone is set to UTC, it considers the 2017-01-24 date as being rooted at UTC, at midnight, zero'ed hours, minutes, and seconds.

Finally, since your system's default time zone is Central Standard Time, ie. UTC-6), when you call toString on the Date object, it'll return a String that is formatted with that time zone, ie. 6 hours before midnight.


Remember also that a Date has no concept of a timezone. It is a timestamp.


To "fix" this, construct your @DateTimeFormat with an appropriate pattern that interprets both time and time zone. I would use

@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX") Date myDate 
Croze answered 27/1, 2017 at 20:42 Comment(3)
This is a great answer. I have one more question. Can I know what's the difference between 'Z' and 'X'? Will it also works with yyyy-MM-dd'T'HH:mm:ss.SSSZ?Peculiarity
@Peculiarity For Date, it uses the SimpleDateFormat pattern characters that are defined here. That explains their purpose.Croze
Thanks. I noticed I didn't read the comment of DateTimeFormat class carefully. It says The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSZ}, e.g. "2000-10-31T01:30:00.000-05:00". Now I understand why I need to use 'X' :)Peculiarity
S
2

For me it works without @JsonFormat when json has the pattern 'yyyy-mm-dd'

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate startDate;
Sansculotte answered 31/3, 2022 at 19:16 Comment(0)
B
0

If you want to configure the time zone in general you can use the following:

 spring.jackson.time-zone=EST

The documentation indicates: "Time zone used when formatting dates. For instance, 'America/Los_Angeles' or 'GMT+10'".

Bemock answered 31/3, 2021 at 2:21 Comment(0)
C
0

This will work. Tried and tested

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
@JsonFormat(pattern = "MM/dd/yyyy")
private LocalDate startDate;
Collectivism answered 4/10, 2021 at 19:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.