如何在毫秒末位为0时截断末尾零?Java日期格式化优化
Jackson序列化OffsetDateTime自动截断末尾零毫秒问题
我编写了一个将Java对象序列化为JSON字符串的示例程序,使用Jackson处理OffsetDateTime类型字段的序列化,但遇到了毫秒格式的问题:当毫秒末位为0时,输出会保留多余的0(比如2024-01-29T17:23:30.290Z),我期望自动截断末尾的零,输出2024-01-29T17:23:30.29Z;而毫秒末位非0时(比如2024-01-29T17:23:30.821Z)输出正常,不需要修改。
原程序代码
import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import io.vertx.core.json.jackson.DatabindCodec; public class Main { public static void main(String[] args) throws JsonProcessingException { ObjectMapper objectMapper = DatabindCodec.mapper(); JavaTimeModule module = new JavaTimeModule(); module.addSerializer(OffsetDateTime.class, new JsonSerializer<OffsetDateTime>() { @Override public void serialize(OffsetDateTime offsetDateTime, JsonGenerator jsonGenerator, SerializerProvider arg2) throws IOException, JsonProcessingException { jsonGenerator.writeString( DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(offsetDateTime)); } }); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); objectMapper.setDateFormat(dateFormatter); objectMapper.registerModule(module); TestOffsetDateTime s1 = new TestOffsetDateTime(); System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(s1)); } public static class TestOffsetDateTime { private OffsetDateTime offSetField; public TestOffsetDateTime() { this.offSetField = OffsetDateTime.now(); } public OffsetDateTime getOffSetField() { return offSetField; } public void setOffSetField(OffsetDateTime offSetField) { this.offSetField = offSetField; } } }
原输出结果
{ "offSetField" : "2024-01-29T17:23:30.290Z" }
需求说明
- 可接受的输出格式:
2024-01-29T17:23:30.821Z(毫秒三位非零)2024-01-29T17:23:30.29Z(毫秒末位0截断为两位)
- 需要修正的情况:
2024-01-29T17:23:31.820Z→ 期望输出2024-01-29T17:23:31.82Z2024-01-29T17:23:31.290Z→ 期望输出2024-01-29T17:23:31.29Z
解决方案
问题出在固定模式SSS会强制输出三位毫秒,不管末尾是否为0。我们需要用DateTimeFormatterBuilder构建动态格式化规则,指定毫秒部分最多保留三位,自动截断末尾的零,最少保留一位(若有毫秒值)。
修改后的序列化器代码
替换原程序中OffsetDateTime序列化器的格式化逻辑:
module.addSerializer(OffsetDateTime.class, new JsonSerializer<OffsetDateTime>() { @Override public void serialize(OffsetDateTime offsetDateTime, JsonGenerator jsonGenerator, SerializerProvider arg2) throws IOException, JsonProcessingException { // 构建动态格式化器,自动截断毫秒末尾的零 DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendPattern("yyyy-MM-dd'T'HH:mm:ss") // 指定毫秒字段:最小1位,最大3位,自动截断末尾零 .appendFraction(ChronoField.MILLI_OF_SECOND, 1, 3, true) .appendLiteral("Z") .toFormatter(); jsonGenerator.writeString(formatter.format(offsetDateTime)); } });
额外优化
如果你的程序中没有java.util.Date类型的字段,可以移除以下冗余代码,避免不必要的配置:
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); objectMapper.setDateFormat(dateFormatter);
修改后运行程序,就能得到符合需求的JSON输出,毫秒末尾的零会被自动截断,非零的毫秒部分完整保留。
内容的提问来源于stack exchange,提问作者Starbucks Admin
相关产品推荐
相关产品推荐

