I have a problem with displaying dates in JSON output. In code I use java.util.Date
and its value is 2019-03-07
but in JSON I got 2019-03-06
Date
is outdated class and should not be used since Java 8
released java.time
package or we can use Joda-Time. You are converting date from Timestamp
to java.sql.Date
and later to java.util.Date
. This is very unsafe, see below example:
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// Java time precise dates
LocalDate localDateOpened = LocalDate.of(2019, 03, 07);
LocalDate localDateClosed = localDateOpened.plusDays(20);
ZoneId utc = ZoneId.of("UTC");
Date opened = Date.from(localDateOpened.atStartOfDay(utc).toInstant());
Date closed = Date.from(localDateClosed.atStartOfDay(utc).toInstant());
System.out.println("Dates generated from java.time.*");
System.out.println(mapper.writeValueAsString(new ThisDay(opened, closed)));
// Calculate dates with default timezone
Calendar calendar = Calendar.getInstance();
opened = calendar.getTime();
calendar.add(Calendar.DAY_OF_MONTH, 20);
closed = calendar.getTime();
System.out.println("Dates generated from Calendar");
System.out.println(mapper.writeValueAsString(new ThisDay(opened, closed)));
// Calculate dates with UTC timezone
calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone(utc));
calendar.set(Calendar.MILLISECOND, 0); // Recompute
opened = calendar.getTime();
calendar.add(Calendar.DAY_OF_MONTH, 20);
closed = calendar.getTime();
System.out.println("Dates generated from UTC Calendar");
System.out.println(mapper.writeValueAsString(new ThisDay(opened, closed)));
}
}
class ThisDay {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date opened;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date closed;
public ThisDay(Date opened, Date closed) {
this.opened = opened;
this.closed = closed;
}
public Date getOpened() {
return opened;
}
public void setOpened(Date opened) {
this.opened = opened;
}
public Date getClosed() {
return closed;
}
public void setClosed(Date closed) {
this.closed = closed;
}
}
Above code prints:
Dates generated from java.time.*
{
"opened" : "2019-03-07 00:00:00",
"closed" : "2019-03-27 00:00:00"
}
Dates generated from Calendar
{
"opened" : "2019-03-27 23:45:12",
"closed" : "2019-04-16 22:45:12"
}
Dates generated from UTC Calendar
{
"opened" : "2019-03-28 00:45:12",
"closed" : "2019-04-17 00:45:12"
}
Notice that second and third opened
dates has difference one hour. I manually set calendar timezone to UTC
and force to recompute values setting milliseconds to 0
:
calendar.setTimeZone(TimeZone.getTimeZone(utc));
calendar.set(Calendar.MILLISECOND, 0); // Recompute
This is why Date
is outdated and java.time
package should be used. If you do not want to show time, only date - change format to @JsonFormat(pattern = "yyyy-MM-dd")
.
See also: