使用 SpringData-MongoDB 将 Java 8 Instant 存储为 BSON 日期

Posted

技术标签:

【中文标题】使用 SpringData-MongoDB 将 Java 8 Instant 存储为 BSON 日期【英文标题】:Store Java 8 Instant as BSON date using SpringData-MongoDB 【发布时间】:2015-01-21 08:57:20 【问题描述】:

我有以下类,我想使用 Spring Data 将其存储在 MongoDB 中

@Document()
public class Tuple2<T extends Enum<T>> 

@Id
private String id;

@Indexed
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private final Instant timeCreated;

...

DateTimeFormat 注释 javadoc 状态:

声明应将字段格式化为日期时间。 支持按样式模式、ISO 日期时间模式或自定义格式模式字符串格式化。可应用于 java.util.Date、java.util.Calendar、java.long.Long、Joda-Time 值类型;从 Spring 4 和 JDK 8 开始,到 JSR-310 java.time 类型也是如此。

我使用的是 Spring 4.1.1 和 JDK 8,所以我希望它适用于 Instant。但是,实际存储的内容如下:

"timeCreated" : 
    "seconds" : NumberLong(1416757496),
    "nanos" : 503000000

如果我按照this answer 中的说明编写并注册从 Instant 到 Date 的自定义转换器,那么它可以工作,但是我想避免这种情况,因为我确信一定有更好的方法。

在进一步挖掘 Spring 源代码后,我发现以下类 Jsr310DateTimeFormatAnnotationFormatterFactory 看起来很有希望:

使用 JDK 8 中的 JSR-310 java.time 包格式化带有 DateTimeFormat 注释的字段。

它的源没有引用Instant,但它确实引用了OffsetTime 和LocalTime。即便如此,当我在示例中将 Instant 更改为 OffsetDateTime 时,它​​仍然存储为复合对象而不是 ISODate。

缺少什么?

【问题讨论】:

【参考方案1】:

我认为问题在于您尝试使用 Instant 作为时间。从概念上讲,它是时间线的一个点,并不意味着格式化。

正如我们所知,Java 8 time API 的开发着眼于 joda-time(并有 joda-time 的开发人员参与)。这是来自joda-time Instant的评论:

Instant 应该用来表示一个时间点 与任何其他因素无关,例如年表或时区。

这就是为什么 org.joda.time.InstantJodaDateTimeFormatAnnotationFormatterFactory 中没有格式化可能性的原因,自 3.0 版以来出现在 Spring 中。而且它也没有在Jsr310DateTimeFormatAnnotationFormatterFactory中实现

所以,你应该使用自定义转换器或考虑使用更合适的类。

【讨论】:

看起来很合理。不过Jsr310DateTimeFormatAnnotationFormatterFactory中有OffsetDateTime,但也没有格式化 @Vic DateTimeFormat 注解不负责存储(mongodb)中的格式化。它适用于应用程序级别(例如 JSP 页面上的格式化)。有用于将数据转换为适当类型的转换器。对于 Java 8 时间 API,我只找到了 ZonedDateTimeToCalendarConverter。那么你可以尝试使用 ZonedDateTime 吗?【参考方案2】:

我对所有时间戳类型的数据使用 Instant,就像您的 timecreated 一样。如果它是针对最终用户的,例如日历条目,则 LocalDateTime 效果更好,但它们都可以使用 ISO 格式的时间字符串创建。在某些时候,需要对时间点数据(日期或即时)进行格式化以提高可读性或序列化/可移植性。

因此,如果有人在当前 MongoDB 版本中遇到此问题,则要回答此问题,您无需在代码中执行任何操作。我使用 init 脚本在我的 mongodb 容器中初始化了一些数据。我使用了 ISODate 格式。

 "timestamp": ISODate("2020-03-17T13:50:56.618Z")

我还有一个 Spring Boot 2 和 Spring Data 应用程序。该文档完全支持它。 https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mapping-conversion

【讨论】:

以上是关于使用 SpringData-MongoDB 将 Java 8 Instant 存储为 BSON 日期的主要内容,如果未能解决你的问题,请参考以下文章

将“-j”参数从 gradle 传递给 ninja

“使用驱动器中J:的光盘之前需要将其格式化

如何通过 Maven 将“-J”选项传递给 javac?

Apache 背后的 Tomcat:将 SSL 与 j_security_check 结合使用

不使用strcat函数,编写一个程序将两个字符串连接起来

使用 Matlab 将矩阵保存到 .dat 文件 [关闭]