问题出现:
你们猜这个对象json序列化之后是什么?
LocalDateTime localDateTime=LocalDateTime.parse("2022-11-09 11:11:11.000", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));
是这个:2022-11-09 11:11:11.000?
这个:2022-11-09T11:11:11.000?
都不是!
是:2022-11-09T11:11:11
那我们去掉中间的T进行解析的化会怎么样呢?LocalDateTime.parse("2022-11-09 11:11:11",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));
直接报错
Exception in thread "main" java.time.format.DateTimeParseException: Text '2022-11-09 11:11:11' could not be parsed at index 19 at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949) at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851) at java.time.LocalDateTime.parse(LocalDateTime.java:492)
这就比较尴尬了,这个错误藏得很深,只有在毫秒值为0时才会出现,测试大概率都不能测试到,我也是业务跑了很长时间才出现了一次。(想嘲讽的人先看后面题外话)
一些源码
jackson
g.writeNumber(value.getYear());
g.writeNumber(value.getMonthValue());
g.writeNumber(value.getDayOfMonth());
g.writeNumber(value.getHour());
g.writeNumber(value.getMinute());
int secs = value.getSecond();
int nanos = value.getNano();
if (secs > 0 || nanos > 0) {
g.writeNumber(secs);
if (nanos > 0) {
if (this.useNanoseconds(provider)) {
g.writeNumber(nanos);
} else {
g.writeNumber(value.get(ChronoField.MILLI_OF_SECOND));
}
}
}
fastjson
if (format == null) {
if ((features & mask) != 0 || serializer.isEnabled(SerializerFeature.UseISO8601DateFormat)) {
format = formatter_iso8601_pattern;
} else {
int nano = dateTime.getNano();
if (nano == 0) {
format = formatter_iso8601_pattern;
} else if (nano % 1000000 == 0) {
format = formatter_iso8601_pattern_23;
} else {
format = formatter_iso8601_pattern_29;
}
}
}
private final static String formatter_iso8601_pattern = "yyyy-MM-dd'T'HH:mm:ss";
解决方案:
jackson
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS")
fastjson
@JSONField(format = "yyyy-MM-dd'T'HH:mm:ss.SSS")
题外话
有些朋友肯定要说,你反序列化不用json框架(jackson、fastjson),自己在那儿乱写,活该你出错,我想说你说的很对,但是我们接口返回之后,对方怎么使用有时候不是我们可以控制的,对方就用String接收然后自己解析也是人家的自由,出问题肯定是找我们的,谁让我们自己缺失了毫秒值呢?