为什么在 Java 8 个日期的 Jackson's ObjectMapper 中使用 dateFormat 时,JSON 不排除毫秒数?

Why aren't milliseconds excluded from JSON when using dateFormat in Jackson's ObjectMapper with Java 8 dates?

我想弄清楚为什么 Jackson (2.9.5) 格式的 Java 8 日期不正确。

data class Test(
        val zonedDateTim: ZonedDateTime = ZonedDateTime.now(),
        val offsetDateTim: OffsetDateTime = OffsetDateTime.now(),
        val date: Date = Date(),
        val localDateTime: LocalDateTime = LocalDateTime.now()
)

val mapper = ObjectMapper().apply {
    registerModule(KotlinModule())
    registerModule(JavaTimeModule())
    dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
    enable(SerializationFeature.INDENT_OUTPUT)
}

println(mapper.writeValueAsString(Test()))

根据我提供的日期格式,我希望得到没有毫秒的日期格式,但结果如下所示:

{
  "zonedDateTim" : "2018-07-27T13:18:26.452+02:00",
  "offsetDateTim" : "2018-07-27T13:18:26.452+02:00",
  "date" : "2018-07-27T13:18:26",
  "localDateTime" : "2018-07-27T13:18:26.452"
}

为什么格式化日期中包含毫秒?

dateFormat 仅适用于 Date 个对象 - 其他 3 个对象由 JavaTimeModule 处理,默认使用 ISO 格式。

如果你想要不同的格式,你可以使用:

val format = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");

val javaTimeModule = JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class, LocalDateTimeSerializer(format));
javaTimeModule.addSerializer(ZonedDateTime.class, ZonedDateTimeSerializer(format));
mapper.registerModule(javaTimeModule);

您可能还需要添加 mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);,但我不能 100% 确定是否有必要。

另请注意,使用该格式时,您将丢失时区和偏移量信息。所以你可能想要 Offset/Zoned-DateTimes.

的不同格式

是正确的。这里有一些进一步的想法。

截断

如果您真的根本不需要小数秒,请截断为整秒。

Instant instant = Instant.now().truncatedTo( ChronoUnit.SECONDS ) ;
OffsetDateTime odt = OffsetDateTime.now().truncatedTo( ChronoUnit.SECONDS ) ;
ZonedDateTime zdt = ZonedDateTime.now().truncatedTo( ChronoUnit.SECONDS ) ;

如果值为零,各种 toString 方法使用的格式化程序默认会省略任何表示小数秒的文本。

因此值为:

2018-07-27T13:18:26.452+02:00

…变成:

2018-07-27T13:18:26.000+02:00

…及其 String 表示将生成为没有小数的秒数:

2018-07-27T13:18:26+02:00

试一试。

OffsetDateTime odt = OffsetDateTime.parse( "2018-07-27T13:18:26.452+02:00" ) ;
OffsetDateTime odtTrunc = odt.truncatedTo( ChronoUnit.SECONDS ) ;

System.out.println( "odt.toString(): " + odt ) ;
System.out.println( "odtTrunc.toString(): " + odtTrunc ) ;

试试 code live at IdeOne.com.

odt.toString(): 2018-07-27T13:18:26.452+02:00

odtTrunc.toString(): 2018-07-27T13:18:26+02:00

避免遗留问题 类

你问题中的代码让我很困惑。不要将麻烦的旧式日期时间 类(例如 Date & SimpleDateFormat 与现代的 java.time 类.旧版 类 已完全被现代版取代。

时间线

请注意,LocalDateTimeInstantOffsetDateTimeZonedDateTime 的用途截然不同。 LocalDateTime 对象故意缺少任何时区或与 UTC 的偏移量的概念。所以它不能代表一个时刻,不是时间轴上的一个点。


关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time 类.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

您可以直接与数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* 类.

java.time类在哪里获取?

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.