使用 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.Instant
在 JodaDateTimeFormatAnnotationFormatterFactory
中没有格式化可能性的原因,自 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 日期的主要内容,如果未能解决你的问题,请参考以下文章