Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
590 views
in Technique[技术] by (71.8m points)

java - Problem with timezone in Json response from Spring

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 23:00:00. I think the problem is in timezone, but I don't use timezones in DB and in code too.

I was trying to fix it with

@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss", timezone="UTC")

and

@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss", timezone="Europe/Warsaw")

The first didn't help, the second helped but I don't accept this solution.

Part of my controller:

return new ThisDay(
    sysoperMgr.getToday(),
    new Date()
);

This is object which I return.

@Getter
@Setter
public class ThisDay {

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    Date dataZamkniecia;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    Date dataSystemowa;

    public BiezacaDoba(Date dataZamkniecia, Date dataSystemowa) {
        this.dataZamkniecia = dataZamkniecia;  // cdate = 2019-03-07T00:00:00.000+0100
        this.dataSystemowa = dataSystemowa; // cdate = 2019-03-27T16:08:12.343+0100
    }
}

This function gets date:

public Date getToday() {

    Timestamp timestamp = sysoperDao.getDataOstatniejZamknietejDoby(); // cdate = 2019-03-06T00:00:00.000+0100
    java.util.Date lastDay = new java.sql.Date(misc.roundTimestamp(timestamp).getTime()); // cdate = 2019-03-06T00:00:00.000+0100
    java.util.Date thisDay = misc.incrementDate(ostatniaDoba, Increment.DAILY, 1); // cdate = 2019-03-07T00:00:00.000+0100
    return thisDay;
}

Json result:

{
  "dataZamkniecia":"2019-03-06 23:00:00",
  "dataSystemowa": "2019-03-27 15:12:15"
}

How do yo get the JSON to display the date always in the local timezone?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...