0

我知道在成千上万的开发人员每天使用的库中发现错误是冒昧的。所以我认为我的标题问题的答案是“不!!!”,但是......

我有一个对象,其中包含从前端 (JS) 收到的日期,并将其存储到 MongoDB 数据库中。我使用 Spring 来获取这个对象(使用 REST 控制器),并使用 Spring 来执行持久性(使用 MongoDBRepository)。我的计算机配置了 CEST 时钟,因此 GMT+2 (UTC +0200)。

我的 POJO 中的日期存储在 LocalDateTime 中。

这是我的对象:

class Test{
  LocalDateTime when;
  String data;
  // getter setters...
}

以下单元测试显示 Spring(使用 jackson-jsr310)用 UTC 日期时间填充我的 LocalDateTime。

mockMvc.perform(post("/test")
        .contentType(MediaType.APPLICATION_JSON_UTF8)
        .content("{\"when\":\"2017-03-31T14:20:28.000Z\",\"data\":\"toto\"}")).andExpect(status().isOk());

List<com.robopec.models.Test> tests =  testRepository.findAll();
Assert.assertEquals(14, tests.get(0).getWhen().getHour());

我们可以在杰克逊源代码LocalDateTimeDeserializer.java的第 74 行看到:

 return LocalDateTime.ofInstant(Instant.parse(string), ZoneOffset.UTC);

但是当我保存在我的数据库中时,spring 使用 spring-data-commons 将我的 LocalDateTime 转换为 Date ,然后再将日期存储在数据库中。我们可以在spring-data-commons/../Jsr310Converters.java中阅读:

public static enum LocalDateTimeToDateConverter implements Converter<LocalDateTime, Date> {
        INSTANCE;
        @Override
        public Date convert(LocalDateTime source) {
            return source == null ? null : Date.from(source.atZone(systemDefault()).toInstant());
        }
    }

因此,spring-data JSR310 转换器将 localdatetime 解释为默认系统区域中的瞬间。

问题是当我的前端发送“2017-04-03T20:00:00Z”时,REST 控制器将其存储在 LocalDateTime 中,时间如下:20:00:00。而当 mongo-data 转换器将其转换为日期时,得到的时间是 20:00:00+0200(因为我的电脑在 CEST 时区)。

我的结论是我不应该将我的日期存储在 LocalDateTime 中,而应该存储在 Date (java.util) 或 Instant 中。

但是,其中一个转换器是否存在错误?

4

1 回答 1

3

如果我没记错的话,最新版本的 mongoDB 的 Java 驱动程序仍然使用 java.util.Date 来存储日期,所以使用 Java 8 时间 api 可能有点麻烦。

在我从事的一个项目中,几个月前我从 Joda Datetime 切换到 Java 8 时间。我无法使用 LocalDateTime、ZonedDateTime 等,所以我决定使用Instant,它运行良好。请记住对您的日期使用 ISO8601 Zulu 表示法(“2017-03-31T14:20:28.000Z”),这显然已经是您正在做的事情了。

于 2017-04-04T08:24:05.813 回答