有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我怎样才能解决这个问题


共 (2) 个答案

  1. # 1 楼答案

    根本没有问题

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

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

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

  2. # 2 楼答案

    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转换为现代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)