0

有一个XMLGregorianCalendar包含该值的对象"2021-01-18T18:43:26.884Z"(这是它的输出toString())。当我尝试用杰克逊序列化这个日期时,我在输出中得到一个 3 小时后的日期:

XMLGregorianCalendar date = ...;
ObjectMapper mapper = new ObjectMapper();

String out = mapper.writeValueAsString(obj); // Output: 1610995406884 (Converted to Date: Mon Jan 18 21:43:26 MSK 2021)

我怎么解决这个问题?

4

2 回答 2

3

完全没有问题。

"2021-01-18T18:43:26.884Z"您的时间XMLGregorianCalendar 是 GMT 时区(格林威治标准时间,伦敦)或 UTC+0(因为尾随Z)的 18:43。

另一方面,您有一个Date带有字符串表示的对象 "Mon Jan 18 21:43:26 MSK 2021",即 MSK 时区(莫斯科标准时间)或 UTC+3 中的 21:43。该类Date选择这个时区来格式化输出只是因为您的计算机位于莫斯科附近。

所以两者实际上是相同的时间点,只是针对两个不同的时区进行了字符串化。

于 2021-01-18T16:01:58.800 回答
2

java.util.Date表示自纪元以来的毫秒数

java.util.Date对象不是像现代日期时间类型那样的真实日期时间对象;相反,它表示自称为“纪元” January 1, 1970, 00:00:00 GMT(或 UTC)的标准基准时间以来的毫秒数。当您打印 的对象时java.util.Date,其toString方法会返回 JVM 时区中的日期时间,根据此毫秒值计算得出。如果您需要在不同的时区打印日期时间,则需要将时区设置为SimpleDateFormat并从中获取格式化字符串。

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(1610995406884L);
        Date date = calendar.getTime();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        System.out.println(sdf.format(date));
        sdf.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
        System.out.println(sdf.format(date));
    }
}

输出:

2021-01-18T18:43:26.884
2021-01-18T21:43:26.884

请注意,日期时间 APIjava.util及其格式化 APISimpleDateFormat已过时且容易出错。建议完全停止使用它们并切换到现代日期时间 API

使用以下命令将传统转换java.util.Date为现代:java.time.Instantjava.util.Date#toInstant

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;

public class Main {
    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(1610995406884L);
        Date date = calendar.getTime();
        Instant instant = date.toInstant();
        System.out.println(instant);

        // You can convert Instant to other types e.g.
        ZonedDateTime zdt = instant.atZone(ZoneId.of("Europe/Moscow"));
        // Print default format i.e. the value of zdt#toString
        System.out.println(zdt);
        // Custom format
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss'['z']'");
        String formatted = dtf.format(zdt);
        System.out.println(formatted);
    }
}

输出:

2021-01-18T18:43:26.884Z
2021-01-18T21:43:26.884+03:00[Europe/Moscow]
2021-01-18T21:43:26[MSK]

Z代表并Zulu代表 UTC(或 GMT)。

于 2021-01-18T15:58:08.433 回答