有些时候,我们在写入mongo数据的时候,可能需要记录这条数据的插入时间,我们一般情况下回给记录增加一个 create_time。
实际上,如果我们插入的数据含有 ObjectId
的话,那么其实这个id是包含了生成时间的,同时也可以作为记录的主键,一举多得。
以python为例,我们有这样一条记录:
document = {
"_id": ObjectId("5dfc8ac5d3fa12967b8888ec"),
"user": "mike",
"age": 19,
}
这时候,我们可以使用ObjectId
自带的generation_time
属性,获取这条记录的插入时间:
time = ObjectId("5dfc8ac5d3fa12967b8888ec").generation_time
print(time)
输出:
datetime.datetime(2019, 12, 20, 8, 48, 5, tzinfo=<bson.tz_util.FixedOffset object at 0x7f874030f9a0>)
需要注意到的是,里面的时区信息,显示的是一个 FixedOffset,即固定偏移,我们看 generation_time
属性的定义:
utc = FixedOffset(0, "UTC")
"""Fixed offset timezone representing UTC."""
class ObjectId(object):
# ... 省略其他代码 ...
@property
def generation_time(self):
"""A :class:`datetime.datetime` instance representing the time of
generation for this :class:`ObjectId`.
The :class:`datetime.datetime` is timezone aware, and
represents the generation time in UTC. It is precise to the
second.
"""
timestamp = struct.unpack(">I", self.__id[0:4])[0]
return datetime.datetime.fromtimestamp(timestamp, utc)
可以看到这个属性是从一个时间戳生成的,并且生成的时候指定了固定的 UTC-0 时区,而我们是处于东八区,因此,如果直接使用 generation_time
属性的话,得到的时间并非我们当前时区的时间,还需要做一个转化,只需要简单的对 datetime.datetime
对象调用astimezone方法,即可:
ObjectId("5dfc8ac5d3fa12967b8888ec").generation_time.astimezone(None)
# output: datetime.datetime(2019, 12, 20, 16, 48, 5, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800), 'CST'))
可以看到,现在输出的时间信息,跟之前的输出相差了8个小时。调用astimezone
传入None的时候,就会默认转化为我们当前所在的时区(代码运行系统所在的时区,东8)
可能我们不想要看到输出这么一长串的信息,展示出来的时候去掉时区信息,我们可以调用 replace
方法:
ObjectId("5dfc8ac5d3fa12967b8888ec").generation_time.astimezone(None).replace(tzinfo=None)
# output: datetime.datetime(2019, 12, 20, 16, 48, 5)
又或许,我们需要的只是一个整型的时间戳,可以这样做:
import struct
from bson import ObjectId
oid = ObjectId("5dfc8ac5d3fa12967b8888ec")
timestamp = struct.unpack(">I", oid.binary[0:4])[0]
# timestamp = 1576831685