我在Spring Boot应用程序中使用Java 8 DateTime和Jackson jsr 310支持。
我禁用了SerializationFeature。WRITE_DATES_AS_TIMESTAMPS强制Jackson将localDatetime序列化为字符串而不是int数组。
但是我发现一个奇怪的格式问题,当日期时间微秒或非秒结束0。我认为序列化的结果可能等于date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),但事实并非如此,format方法省略了零。
完整的示例测试代码。
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"
}
zonedDate和localDate微秒以00结束,但offsetDate不是。和日期。格式也得到不同的结果,毫秒数NOT以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]
- 似乎toString结果应该是Jackson序列化所需的结果,在上面的日志记录中,OffsetDateTime json节点微秒文本应该以00结束。
- 为什么format方法的结果省略了结尾00?
完整的示例代码可以从我的github.com找到。
angular-springmvc-sample-boot
ISODateTest
作为解决方法,我添加了自己的序列化器:
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);
你的测试有两个问题:
- 你比较苹果和橙子,
ObjectMapper
序列化的结果和DateTimeFormatter
格式化的结果。每个都有自己的默认值和配置选项,结果不同也就不足为奇了。 -
100_000_000
实际上是1
,根据ISO_LOCAL_TIME定义,DateTimeFormatter
打印"纳秒1到9位数字"。根据需要输出任意数量的数字。"在您的情况下,只需要1位数字,这正是您在LocalDateTime
的输出中得到的。
我不完全清楚你在这里想做什么,以及你写的测试的目的是什么。如果您希望格式化程序的精度达到3个数字的纳秒级,那么您必须使用自己的格式化程序。在代码中依赖toString
格式是一个坏主意。
下面是我配置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;
}
}