MongoDb BSON将日期存储在UTC时间中。

10
如果我试图将一个日期字段放入一个文档(BSON)并写入Mongo数据库,BSON将其写成UTC格式。例如,一个日期:
DateTime dateTime = new DateTime("2015-07-01");
Document doc = new Document("date", dateTime.toDate());

将被存储为

"date" : ISODate("2015-06-30T18:30:00Z")

在Mongo中,如果我使用相同的Java驱动程序检索它,我会将其作为返回。

Wed Jul 01 00:00:00 IST 2015

很好。这个问题没有解决方案吗?我的意思是,为什么不能按照自己的方式存储日期?如果我需要从另一个时区查询数据库怎么办?我会得到不同的结果吗?日期字段是Mongo的重要组成部分,周围包着丰富的操作符。但是,为什么Mongo不提供这种灵活性呢? 谢谢


如果我需要从另一个时区查询数据库怎么办?你的意思是什么?基本上,“Date”类型表示自Unix纪元以来以毫秒为单位内部存储的时间点。如果您不想存储时间点,“Date”无法帮助您 :( - Jon Skeet
1
一般来说,最好在数据库中将日期保留为UTC时间。也许你应该在API端处理时区。 - Sercan Ozdemir
@JonSkeet 我已经插入了IST区的日期字段。如果我需要从不同的时区查询数据库,那么我不会得到相应的日期时间吗?我该如何将日期存储为原样? - void
仅仅重复“如果我需要从不同的时区查询数据库怎么办?”并没有真正告诉我你的意思。日期值并不知道时区 - 它只是一个时间点。同样,你执行的任何查询都只会将该值与另一个时间点进行比较。我不知道你在这种情况下所说的“原样”,但你需要了解Date类型的含义。你试图实现什么行为并不清楚。 - Jon Skeet
@JonSkeet 可能是时间存储引起了我的问题。我需要将日期存储为“2015-07-01”。并且希望在从印度或伦敦进行查询时,在两种情况下都获得结果为“2015-07-01”。也许Mongo不是我需要的数据库 :( - void
1
实际上,您必须将其存储为不同类型,或解析您的原始日期/时间为UTC(即存储2015-07-01T00:00:00Z)。 - Jon Skeet
5个回答

4

在我看来,Mongo做得非常正确。您使用本地时区实例化日期,然后将其存储为UTC格式的时间戳。当您请求Mongo检索它时,它会再次将日期转换为您的本地时区。

如果您不想处理时区转换,请使用以下标志将本地时区设置为UTC:

-Duser.timezone="UTC"

1
@AswinJoseRoy 将此设置为您的应用程序启动参数,即 java -jar yourApp.jar -Duser.timezone="UTC" - Alex
在我看来,Mongo并没有做到完全正确。我想要持久化一天的时间,而不是一个时间点,因为这个时间点会因时区不同而在不同的日期上表示。如果我想要这样做,我会存储一个时间对象。 - Ekkstein
1
@Ekkstein 抱歉,这不是 datetime 在 Python 或 BSON 中的作用... 它不存储 date,也不存储 timeoffset 或其他任何东西。你要求一种在 BSON 中自然不支持的数据类型。 好消息是:你可以自己创建。使用字符串。使用整数。使用像 {"$date": "2022-02-09"} 这样的对象。 - Dan H

1

当使用DateTime(来自org.joda.timejava.time)创建带有时区的日期时,MongoDB不幸没有支持它。(请参见BSON类型

因此,在UTC中持久化它是一种简单可靠的解决方案,而不会丢失任何数据。

作为替代方案,您应该看看LocalDateTime。 它不包含DateTimeZone,因此无需先进行任何转换。


1
如果您指的是org.joda.time.LocalDateTime,它也无法工作。 - void

0

有一个非常简单的解决方案。在您的MongoDB中让日期保持为UTC。
每当您将其提取到UI时,只需执行以下操作:

new Date(fetchedDate);

它将其转换为本地日期。


0
我通过在代码内部将时区设置为UTC来解决了这个问题。
    DateTimeZone zone = DateTimeZone.UTC;
    DateTimeZone.setDefault(zone);

0

在从MongoDB检索日期时,我遇到了相同的问题。MongoDB遵循UTC时区,因此当您执行任何日期操作时,它会转换为UTC。

因此,我使用了mongoose的post hook来将日期和时间转换为我喜欢的时区。这是代码片段。

schema.post(['find', 'findOne'], async function(docs, next) {
    docs.map((doc) => doc.createdAt= convertToTz({tz: process.env.TZ, date: doc.createdAt}))
    next();
});

在这里,createdAt是文档创建的日期。convertToTz是我下面提到的一个常用函数。

const moment = require("moment-timezone");

const convertToTz = (params) => {
  try {
        let tz = params?.tz ?? process.env.TZ;
        let format = params?.format ?? "";
        return moment(params.date).tz(tz).format(format);
    } catch (error) {
       throw new Error(error);
  }
};

注意:这段代码是使用NodeJs编写的,但我希望它能解决您的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接