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

我有以下类,我想使用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 annotation 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
}

如果我像这个答案中解释的那样编写并注册从即时到日期的自定义转换器,那么它就可以工作了,但是我想避免这种情况,因为我相信一定有更好的方法。

在进一步挖掘Spring源代码之后,我发现了以下看起来很有前途的类:Jsr310DateTimeFormatAnnotationFormatterFactory

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

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

缺少什么?


答案 1

我认为问题在于你试图使用什么时间。从概念上讲,它是时间轴的一个点,并不意味着格式。Instant

正如我们所知,Java 8 time API是在joda-time(以及joda-time开发人员的参与下)开发的。以下是joda-time的评论:Instant

即时应用于表示时间点,而不考虑任何其他因素,例如时间顺序或时区。

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

因此,您应该使用自定义转换器或考虑使用更合适的类。


答案 2

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

因此,要回答这个问题,如果有人在当前的MongoDB版本中遇到这个问题,你不需要在代码中做任何事情。我使用初始化脚本在我的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


推荐