2

我在 Spring Boot 应用程序中使用 Java 8 DateTime 和 Jackson jsr 310 支持。

我禁用 了SerializationFeature.WRITE_DATES_AS_TIMESTAMPS以强制杰克逊将 localDatetime 序列化为字符串而不是 int 数组。

但是当日期时间微秒或非秒为0结尾时,我发现了一个奇怪的格式问题。我认为序列化结果可能等于date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),但事实并非如此,格式方法省略了零。

完整的示例测试代码。

private LocalDateTime date;

private OffsetDateTime offsetDate;

private ZonedDateTime zonedDate;

@Before
public void setup() throws ServletException {
    date = LocalDateTime.of(2015, 8, 15, 11, 40, 10, 100_000_000);
    offsetDate = OffsetDateTime.of(2015, 8, 15, 11, 40, 10, 100_000_000, ZoneOffset.ofHours(8));
    zonedDate = ZonedDateTime.of(2015, 8, 15, 11, 40, 10, 100_000_000, ZoneId.of("Asia/Shanghai"));
}

@Test
public void testDateFormat() throws Exception {
    Map<String, Object> map = new HashMap<>();
    map.put("localDate", date);
    map.put("offsetDate", offsetDate);
    map.put("zonedDate", zonedDate);

    String json = objectMapper.writeValueAsString(map);

    log.debug("converted json result @" + json);

    JsonNode rootNode = objectMapper.readTree(json);

    JsonNode localDateNode = rootNode.get("localDate");
    assertEquals("local date should be equals", date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME), localDateNode.textValue());

    JsonNode offsetDateNode = rootNode.get("offsetDate");
    assertEquals("offsetDate date should be equals", offsetDate.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME), offsetDateNode.textValue());

    JsonNode zonedDateNode = rootNode.get("zonedDate");
    assertEquals("zonedDate date should be equals", zonedDate.format(DateTimeFormatter.ISO_ZONED_DATE_TIME), zonedDateNode.textValue());

}

测试失败,日志调试打印

{
    "zonedDate":"2015-08-15T11:40:10.100+08:00[Asia/Shanghai]",
    "localDate":"2015-08-15T11:40:10.100",
    "offsetDate":"2015-08-15T11:40:10.1+08:00"
}

zonedDatelocalDate微秒以00结尾,但 offsetDate 不是。并且date.format也得到不同的结果,其中 micrseconds不以00结尾。

format、toString、json文本的打印结果

LocalDateTime format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)@2015-08-15T11:40:10.1
LocalDateTime toString                                     @2015-08-15T11:40:10.100
LocalDateTime serialized json node text                    @2015-08-15T11:40:10.100
OffsetDateTime format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)@2015-08-15T11:40:10.1+08:00
OffsetDateTime toString                                      @2015-08-15T11:40:10.100+08:00
OffsetDateTime serialized json node text                     @2015-08-15T11:40:10.1+08:00
ZonedDateTime format(DateTimeFormatter.ISO_ZONED_DATE_TIME)@2015-08-15T11:40:10.1+08:00[Asia/Shanghai]
ZonedDateTime toString                                     @2015-08-15T11:40:10.100+08:00[Asia/Shanghai]
ZonedDateTime serialized json node text                    @2015-08-15T11:40:10.100+08:00[Asia/Shanghai]
  1. 似乎toString结果应该是 Jackson 序列化中的期望结果,在上面的日志记录中,OffsetDateTime json 节点微秒文本应该以00结尾。
  2. 为什么格式方法结果省略了结尾00

完整的示例代码可以从我的 github.com 找到。

角-springmvc-sample-boot

ISODateTest

4

3 回答 3

3

作为一种解决方法,我添加了自己的序列化程序:

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new JavaTimeModule());
    SimpleModule module = new SimpleModule();
    module.addSerializer(ZonedDateTime.class, new JsonSerializer<ZonedDateTime>() {
        @Override
        public void serialize(ZonedDateTime zonedDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
            jsonGenerator.writeString(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZ").format(zonedDateTime));
        }
    });
    objectMapper.registerModule(module);
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
于 2016-02-29T13:15:48.750 回答
0

这是我为配置 ObjectMapper 所做的。

@Configuration
public class JacksonConfiguration {

  @Bean
  public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    ObjectMapper objectMapper = builder.build();
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
    return objectMapper;
  }
}
于 2016-08-28T15:31:51.020 回答
0

您的测试有两个问题:

  1. 您将苹果与橙子、ObjectMapper序列化结果和DateTimeFormatter格式化结果进行比较。每个都有自己的默认值和配置选项,结果不同也就不足为奇了。
  2. 100_000_000是真的1并且根据ISO_LOCAL_TIME定义,DateTimeFormatter打印“一到九位数字为纳秒。将根据需要输出尽可能多的数字。”。在您的情况下,只需要 1 位数字,这正是您在输出中得到的LocalDateTime.

我不完全清楚您在这里尝试做什么以及您编写的测试的目的是什么。如果您希望格式化程序达到 3 位数的纳秒精度,那么您必须自己动手。取决于toString代码中的格式是一个坏主意。

于 2015-10-18T07:41:07.803 回答