微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Jackson 错误地序列化了 XMLGregorianCalendar

如何解决Jackson 错误地序列化了 XMLGregorianCalendar

一个 XMLGregorianCalendar 对象包含值 "2021-01-18T18:43:26.884Z"(这是它在 toString() 中的输出)。当我尝试用 Jackson 序列化这个日期时,我在 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)

我该如何解决这个问题?

解决方法

完全没有问题。

"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 类选择了这个时区来格式化输出 仅仅是因为您的计算机位于莫斯科附近。

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

,

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

java.util.Date 对象不是像 modern date-time types 那样的真实日期时间对象;相反,它表示自称为“纪元”的标准基准时间以来的毫秒数,即 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

请注意,java.util 的日期时间 API 及其格式 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到 modern date-time API

使用 java.util.Date#toInstant 将传统 java.util.Date 转换为现代 java.time.Instant

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)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。