work-notes

测试代码:

package com.sanss.prc.alarm.jul;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp;

import lombok.extern.slf4j.Slf4j;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Date;

import javax.annotation.Resource;

@SpringBootTest
@Slf4j
public class DatePrintTest {

   plain @Resource ObjectMapper objectMapper;

   plain @Test
    void testDatePrint() throws JsonProcessingException {
        // serialize test
        MeetingScreenOrderResp.Record record = new MeetingScreenOrderResp.Record();
        record.setOrderTime(new Date());
        log.info("log info print:{}", record.getOrderTime());
        log.info("obj mapper:{}", objectMapper.writeValueAsString(record.getOrderTime()));

        // deserialize test
        String[] dateFormats = {"\"2024-07-30 14:30:00\"", "\"2024-07-30T14:30:00\"", "\"2024-07-30T14:30:00Z\"",
                "\"2024-07-30T14:30:00+08:00\"", "1722504600000"  // 毫秒时间戳
        };

        for (String dateStr : dateFormats) {
            try {
                MeetingScreenOrderResp.Record dto =
                        objectMapper.readValue("{\"orderTime\": " + dateStr + "}", MeetingScreenOrderResp.Record.class);
                log.info("成功解析: {} => {}", dateStr, dto.getOrderTime());
            } catch (Exception e) {
                log.info("解析失败: {} - {}", dateStr, e.getMessage());
            }
        }

    }
}

1.情况一

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 自定义日期序列化
        // SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // objectMapper.setDateFormat(df);
        // 关闭反序列化时写入时间戳
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        // 未知属性不报错
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        return objectMapper;
    }
    pojo:
            /**
         * 订单时间(格式:yyyy-MM-dd hh:mm:ss)。
         */
        // @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private Date orderTime;

1.1 情况一测试结果

2024-07-30 10:48:54  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:27 : log info print:Tue Jul 30 10:48:54 SGT 2024
2024-07-30 10:48:54  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:28 : obj mapper:"2024-07-30T10:48:54.930+08:00"
2024-07-30 10:48:54  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30 14:30:00" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30 14:30:00": not a valid representation (error: Failed to parse Date value '2024-07-30 14:30:00': Cannot parse date "2024-07-30 14:30:00": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSX', parsing fails (leniency? null))
 at [Source: (String)"{"orderTime": "2024-07-30 14:30:00"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 10:48:54  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: "2024-07-30T14:30:00" => Tue Jul 30 14:30:00 SGT 2024
2024-07-30 10:48:54  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: "2024-07-30T14:30:00Z" => Tue Jul 30 22:30:00 SGT 2024
2024-07-30 10:48:54  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: "2024-07-30T14:30:00+08:00" => Tue Jul 30 14:30:00 SGT 2024
2024-07-30 10:48:54  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: 1722504600000 => Thu Aug 01 17:30:00 SGT 2024

1.2 情况一测试结果说明

objectMapper 未设置 dateformat,@jsonFormat 注解未生效

1.2.1 序列化行为

2024-07-30T10:48:54.930+08:00

1.2.1 反序列化行为

日期字符串 解析结果
“2024-07-30 14:30:00” 解析失败
“2024-07-30T14:30:00” 成功解析
“2024-07-30T14:30:00Z” 成功解析
“2024-07-30T14:30:00+08:00” 成功解析
1722504600000 成功解析

2.情况二

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 自定义日期序列化
        // SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // objectMapper.setDateFormat(df);
        // 关闭反序列化时写入时间戳
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        // 未知属性不报错
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        return objectMapper;
    }
    pojo:
            /**
         * 订单时间(格式:yyyy-MM-dd hh:mm:ss)。
         */
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private Date orderTime;

2.1 情况二测试结果

2024-07-30 10:50:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:27 : log info print:Tue Jul 30 10:50:32 SGT 2024
2024-07-30 10:50:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:28 : obj mapper:"2024-07-30T10:50:32.868+08:00"
2024-07-30 10:50:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: "2024-07-30 14:30:00" => Tue Jul 30 14:30:00 SGT 2024
2024-07-30 10:50:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00": expected format "yyyy-MM-dd HH:mm:ss"
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 10:50:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00Z" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00Z": expected format "yyyy-MM-dd HH:mm:ss"
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00Z"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 10:50:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00+08:00" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00+08:00": expected format "yyyy-MM-dd HH:mm:ss"
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00+08:00"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 10:50:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: 1722504600000 => Thu Aug 01 17:30:00 SGT 2024

2.2 情况二测试结果说明

objectMapper 未设置 dateformat,@jsonFormat 注解生效

2.2.1 序列化行为

2024-07-30T10:50:32.868+08:00

2.2.2 反序列化行为

日期字符串 解析结果
“2024-07-30 14:30:00” 解析成功
“2024-07-30T14:30:00” 解析失败
“2024-07-30T14:30:00Z” 解析失败
“2024-07-30T14:30:00+08:00” 解析失败
1722504600000 成功解析

3.情况三

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 自定义日期序列化
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        objectMapper.setDateFormat(df);
        // 关闭反序列化时写入时间戳
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        // 未知属性不报错
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        return objectMapper;
    }
    pojo:
            /**
         * 订单时间(格式:yyyy-MM-dd hh:mm:ss)。
         */
        // @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private Date orderTime;

3.1 情况三测试结果

2024-07-30 10:53:22  INFO [alarm,,] --- [       Thread-7] com.xxl.job.core.server.EmbedServer     .run:82 : >>>>>>>>>>> xxl-job remoting server start success, nettype = class com.xxl.job.core.server.EmbedServer, port = 9999
2024-07-30 10:53:23  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:27 : log info print:Tue Jul 30 10:53:23 SGT 2024
2024-07-30 10:53:23  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:28 : obj mapper:"2024-07-30 10:53:23"
2024-07-30 10:53:23  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: "2024-07-30 14:30:00" => Tue Jul 30 14:30:00 SGT 2024
2024-07-30 10:53:23  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00": not a valid representation (error: Failed to parse Date value '2024-07-30T14:30:00': Unparseable date: "2024-07-30T14:30:00")
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 10:53:23  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00Z" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00Z": not a valid representation (error: Failed to parse Date value '2024-07-30T14:30:00Z': Unparseable date: "2024-07-30T14:30:00Z")
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00Z"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 10:53:23  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00+08:00" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00+08:00": not a valid representation (error: Failed to parse Date value '2024-07-30T14:30:00+08:00': Unparseable date: "2024-07-30T14:30:00+08:00")
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00+08:00"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 10:53:23  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: 1722504600000 => Thu Aug 01 17:30:00 SGT 2024

3.2 情况三测试结果说明

objectMapper 设置 dateformat,@jsonFormat 注解未生效

3.2.1 序列化行为

2024-07-30 10:53:23

3.2.2 反序列化行为

日期字符串 解析结果
“2024-07-30 14:30:00” 解析成功
“2024-07-30T14:30:00” 解析失败
“2024-07-30T14:30:00Z” 解析失败
“2024-07-30T14:30:00+08:00” 解析失败
1722504600000 成功解析

4.情况四

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 自定义日期序列化
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        objectMapper.setDateFormat(df);
        // 关闭反序列化时写入时间戳
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        // 未知属性不报错
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        return objectMapper;
    }
    pojo:
            /**
         * 订单时间(格式:yyyy-MM-dd hh:mm:ss)。
         */
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private Date orderTime;

4.1 情况四测试结果

2024-07-30 10:54:36  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:27 : log info print:Tue Jul 30 10:54:36 SGT 2024
2024-07-30 10:54:36  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:28 : obj mapper:"2024-07-30 10:54:36"
2024-07-30 10:54:36  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: "2024-07-30 14:30:00" => Tue Jul 30 14:30:00 SGT 2024
2024-07-30 10:54:36  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00": expected format "yyyy-MM-dd HH:mm:ss"
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 10:54:36  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00Z" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00Z": expected format "yyyy-MM-dd HH:mm:ss"
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00Z"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 10:54:36  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00+08:00" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00+08:00": expected format "yyyy-MM-dd HH:mm:ss"
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00+08:00"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 10:54:36  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: 1722504600000 => Thu Aug 01 17:30:00 SGT 2024

4.2 情况四测试结果说明

objectMapper 设置 dateformat,@jsonFormat 注解生效

4.2.1 序列化行为

2024-07-30 10:54:36

4.2.2 反序列化行为

日期字符串 解析结果
“2024-07-30 14:30:00” 解析成功
“2024-07-30T14:30:00” 解析失败
“2024-07-30T14:30:00Z” 解析失败
“2024-07-30T14:30:00+08:00” 解析失败
1722504600000 成功解析

5.总结

- objectMapper 设置 dateformat objectMapper 不设置 dateformat
@JsonFormat 字段 注解存在 情况四 情况二
@JsonFormat 字段注解不存在 情况三 情况一

请根据测试,分析 objectMapper 中 dateformat 配置项 以及@jsonformat 注解对于序列化 反序列化的影响

6.补充测试

        /**
         * 订单时间(格式:yyyy-MM-dd hh:mm:ss)。
         */
        @JsonFormat(pattern = "yyyyMMddHHmmss", timezone = "GMT+8")
        private Date orderTime;
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 自定义日期序列化
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        objectMapper.setDateFormat(df);
        // 关闭反序列化时写入时间戳
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        // 未知属性不报错
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        return objectMapper;
    }

6.1 补充测试结果

2024-07-30 11:11:32  INFO [alarm,,] --- [       Thread-7] com.xxl.job.core.server.EmbedServer     .run:82 : >>>>>>>>>>> xxl-job remoting server start success, nettype = class com.xxl.job.core.server.EmbedServer, port = 9999
2024-07-30 11:11:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:27 : log info print:Tue Jul 30 11:11:32 SGT 2024
2024-07-30 11:11:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:28 : obj mapper:"2024-07-30 11:11:32"
2024-07-30 11:11:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: "2024-07-30 14:30:00" => Wed Dec 06 21:00:14 SGT 2023
2024-07-30 11:11:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00": expected format "yyyyMMddHHmmss"
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 11:11:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00Z" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00Z": expected format "yyyyMMddHHmmss"
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00Z"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 11:11:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:41 : 解析失败: "2024-07-30T14:30:00+08:00" - Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00+08:00": expected format "yyyyMMddHHmmss"
 at [Source: (String)"{"orderTime": "2024-07-30T14:30:00+08:00"}"; line: 1, column: 15] (through reference chain: com.sanss.prc.model.alarm.model.dto.response.MeetingScreenOrderResp$Record["orderTime"])
2024-07-30 11:11:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:39 : 成功解析: 1722504600000 => Thu Aug 01 17:30:00 SGT 2024

6.2 补充测试结果说明

反序列化时,JsonFormat 注解的 pattern 优先级高于 objectMapper 的 dateformat 配置,可以从以下错误信息中看出:

Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00": expected format "yyyyMMddHHmmss"

JsonFormat 注解应当对序列化没有帮助,可以从情况二的测试结果中看出

2024-07-30 10:50:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:28 : obj mapper:"2024-07-30T10:50:32.868+08:00"

总结:

对于序列化,objectMapper 来决定,JsonFormat 字段注解对于序列化没有任何帮助,补充测试可以直观看出. jsonformat 指定的格式是 yyyyMMddHHmmss,但是序列化的时候还是按照 objectMapper 指定的 yyyy-MM-dd HH:mm:ss 格式序列化的 对于objectMapper未指定序列化格式时,jsonformat指定的格式也未生效,参照情况二:

2024-07-30 10:50:32  INFO [alarm,,] --- [           main] com.sanss.prc.alarm.jul.DatePrintTest   .testDatePrint:28 : obj mapper:"2024-07-30T10:50:32.868+08:00"

对于反序列化,JsonFormat 字段注解的优先级更高,同样可以从补充测试结果中看出:

Cannot deserialize value of type `java.util.Date` from String "2024-07-30T14:30:00": expected format "yyyyMMddHHmmss"

对于不带@JsonFormat 注解的情况,可以参考情况一,情况三

如果 objectMapper 没有设置 yyyy-MM-dd HH:mm:ss格式,那么这种时间格式无法被反序列化

如果 objectMapper 设置了 yyyy-MM-dd HH:mm:ss格式,那么这种时间格式可以被反序列化

ms 级时间戳无论如何都可以被反序列化

一般来说,为了给前端提供更好的时间格式,一般会在 objectMapper 设置时间格式,那么这种情况下,@JsonFormat 注解其实是可有可无的,情况三四可以佐证