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

alen0pnh  于 2022-11-09  发布在  Java
关注(0)|答案(2)|浏览(99)

我试图弄清楚为什么Jackson(2.9.5)对Java8中的日期格式不正确。

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"
}

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

jaxagkaj

jaxagkaj1#

dateFormat仅适用于Date对象-其他3个对象由JavaTimeModule处理,默认情况下,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%确定它是必要的。
另请注意,使用该格式将丢失时区和偏移量信息。因此,您可能需要一个不同的偏移量/区域日期时间格式。

vybvopom

vybvopom2#

Answer by assylias是正确的。下面是一些进一步的想法。

截断

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

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

如果值为零,则各种toString方法所使用的格式子预设会省略任何表示小数秒的文字。
因此的值为:
2018年7月27日13时18分26.452秒+02时00分
...变成:
2018年7月27日13:18:26.000+02:00
...并且其String表示将生成为不带小数的秒:
2018年7月27日13: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
(a)将字符串转换为字符串; 2018年7月27日13时18分26.452秒+02时00分
字符串类型:2018年7月27日13:18:26+02:00

避免旧类

你的问题中的代码让我很困惑。不要把麻烦的旧的遗留日期-时间类(如Date & SimpleDateFormat)与现代的 java.time 类混合在一起。遗留类完全被现代的类所取代。

时间表

要清楚的是,LocalDateTime的用途与InstantOffsetDateTimeZonedDateTime非常不同。LocalDateTime对象故意不包含时区或UTC偏移量的概念。因此,它 * 不能 * 表示时刻,* 不是 * 时间线上的一个点。

关于 java.time

java.time框架内置于Java 8和更高版本中,这些类取代了麻烦的旧legacy日期-时间类,如java.util.DateCalendarSimpleDateFormat
Joda-Time项目(现在在maintenance mode中)建议迁移到java.time类。
要了解更多信息,请参阅Oracle Tutorial。并搜索Stack Overflow以获取更多示例和说明。规范为JSR 310
您可以直接与数据库交换 java.time 对象。请使用与JDBC 4.2或更高版本兼容的JDBC driver。不需要字符串,也不需要java.sql.*类。
从哪里获得java.time类?

*Java SE 8Java SE 9Java SE 10及更高版本

  • 内建的。
  • 标准Java API的一部分,具有捆绑的实现。
  • Java 9增加了一些小的特性和修复。
    *Java SE 6Java SE 7
  • 许多java.time功能在ThreeTen-Backport中向后移植到Java 6和7。
  • Android
  • 更高版本的Android捆绑了 java.time 类的实现。
  • 对于早期的Android(〈26),ThreeTenABP项目采用了ThreeTen-Backport(如上所述)。请参见How to use ThreeTenABP…

ThreeTen-Extra项目使用附加类扩展了java.time。该项目是将来可能添加到java. time的试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuartermore

相关问题