在MongoDB中存储日期/时间的最佳方法是什么?

213

我见过使用字符串、整数时间戳和Mongo日期时间对象。

5个回答

240

最好的方法是存储本地JavaScript Date对象,这些对象映射到 BSON本机Date对象

> db.test.insert({date: ISODate()})
> db.test.insert({date: new Date()})
> db.test.find()
{ "_id" : ObjectId("..."), "date" : ISODate("2014-02-10T10:50:42.389Z") }
{ "_id" : ObjectId("..."), "date" : ISODate("2014-02-10T10:50:57.240Z") }

原生类型支持一系列非常有用的方法,你可以在map-reduce任务中使用这些方法。

如果需要的话,你可以轻松地将Date对象转换为Unix时间戳或者从Unix时间戳转换成Date对象。具体来说,你可以使用 getTime() 方法和 Date(milliseconds) 构造函数。

1) 严格来说,Unix时间戳是以秒为单位计算的。而JavaScript Date对象是自Unix纪元以来的毫秒数。


9
这将如何存储在数据库中?作为Mongo日期时间对象? - Thilo
3
据我所知,MongoDB没有特殊的“datetime”对象。它使用JavaScript Date类型,并以BSON格式存储。 - Niels van der Rest
2
@Thilo:没错,这基本上就是JavaScript Date对象的BSON表示形式。它是一个64位整数,存储自Unix时代以来的毫秒数,并支持JavaScript规范中的大多数方法。 - Niels van der Rest
1
@AboozarRajabi 389240 是时间戳的毫秒数。在 字符串格式 中的 Z 告诉 MongoDB 提供的时间戳是 UTC 时间。如果您读取它,您的应用程序可能会将其转换为您的 本地 时区,使其似乎时间已经改变。但时间仍然是相同的,只是从不同的时区角度进行解释。例如,12:50:42Z13:50:42+01:00 表示相同的时间点。 - Niels van der Rest
5
一般而言,只要最初的输入正确,你不需要关心数据是如何存储的。如果当前是欧洲中部时间(CET)的21:56:03+01:00,并插入了“new Date()”,那么MongoDB可能会将其表示为“20:56:03Z”。但当你读取它并使用本地时区设置(CET)在你的应用程序中显示它时,它将再次显示为“21:56:03”。 - Niels van der Rest
显示剩余4条评论

62

已经在_id对象中包含了一个日期戳,代表插入时间

因此,如果您需要插入时间,它已经存在:

登录到MongoDB shell

ubuntu@ip-10-0-1-223:~$ mongo 10.0.1.223
MongoDB shell version: 2.4.9
connecting to: 10.0.1.223/test

通过插入项创建您的数据库

> db.penguins.insert({"penguin": "skipper"})
> db.penguins.insert({"penguin": "kowalski"})
> 

让我们将数据库切换到当前使用的这个

> use penguins
switched to db penguins

获取行:

> db.penguins.find()
{ "_id" : ObjectId("5498da1bf83a61f58ef6c6d5"), "penguin" : "skipper" }
{ "_id" : ObjectId("5498da28f83a61f58ef6c6d6"), "penguin" : "kowalski" }

以 yyyy-MM-dd HH:mm:ss 格式获取每一行:

> db.penguins.find().forEach(function (doc){ d = doc._id.getTimestamp(); print(d.getFullYear()+"-"+(d.getMonth()+1)+"-"+d.getDate() + " " + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds()) })
2014-12-23 3:4:41
2014-12-23 3:4:53
如果您对最后一行代码感到困惑,我在这里提供了一个演示它如何工作的步骤: https://dev59.com/nGw15IYBdhLWcg3wtN2O#27613766

32
这个时间戳是文档在数据库中保存的时间,有时您希望存储与插入日期无关的日期和时间。 - Yuval A.
1
如果您的数据库非常快,并且两个文档存储在同一毫秒内,那么这些文档是否具有相同的“_id”? - Redsandro
10
不,但是它们有可能会得到与_id.getTimestamp()相同的结果。 - kmiyashiro
@kmiyashiro,你知道如何根据时间戳进行排序吗? - ledlogic
1
没关系,sort({createdOn:-1}); 是从https://dev59.com/CcHrs4cB2Jgan1znm0Bl使用的方法。 - ledlogic
这是MongoDB生成ID的方式:https://docs.mongodb.com/manual/reference/method/ObjectId/。请注意,它不仅仅是从创建时间戳生成的(时间戳只是前4个字节)。 - diazdeteran

2
我认为当你使用pymongo时,MongoDB会将原生的Python datetime对象存储为Date字段。在MongoDB中,这个Date字段可以方便后续进行与日期相关的查询(例如查询时间间隔)。因此,在Python中,像这样的代码是有效的。
from datetime import datetime

datetime_now = datetime.utcnow()
new_doc = db.content.insert_one({"updated": datetime_now})

在此之后,我可以在我的数据库中看到以下字段(我使用Mongo Compass查看我的数据库)。请注意,它不是作为字符串存储的(没有引号),并且显示Date作为字段类型。

enter image description here

关于JavaScript的使用,这也应该适用。只要你在日期的末尾有+00:00(对我来说是UTC)或Z,JavaScript就应该能够正确读取带有时区信息的日期。

0
使用下面的代码创建一个可以在文档中分配的datetime变量(请注意,我正在创建一个datetime对象,而不是一个date对象):
from datetime import date
from datetime import datetime
import random

def random(date):
    my_year=random.randint(2020,2022)
    my_month=random.randint(1,12)
    my_day=random.randint(1,28)

    selected=datetime(year = my_year, month = my_month, day = my_day, hour = 0, minute = 0, second = 0)


def insert_objects(collection):

      collection.insert_one( { "mydate": random_date() })

0

BSON日期是一个64位整数,表示自Unix纪元(1970年1月1日)以来的毫秒数。这导致了一个可表示的日期范围,大约可以追溯到290亿年前和未来。

官方的BSON规范将BSON日期类型称为UTC日期时间。

BSON日期类型是有符号的。负值表示1970年之前的日期。


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