我有一个带有foo
个对象的MongoDB数据库。我想记录它们添加到数据库的时间。为此,我的方法是存储时间,将foo
添加到数据库并设置开始时间。当我从数据库中获取foo
时,开始时间属性应该与我添加它的时间相匹配。
以下是我的测试,反映了这一点。这些功能并不十分重要,因为它们基本上是db.collection.insert
或db.collection.find_one
来电。
def test_set_foo_start_time(self):
import datetime
t = datetime.datetime.utcnow()
foo_id = "42"
print("\nAdding {0} to the database.".format(t))
add_foo_to_database(foo_id)
self.assertIsNotNone(get_foo_from_database(foo_id))
set_foo_start_time(foo_id, t)
time = get_foo_from_database(foo_id)['start_time']
print("Extracting {0} from the database.".format(time))
self.assertEqual(t, time)
当我进行测试时,我惊讶地发现它失败了:
test_set_foo_start_time (test_foo_misc.FooMiscellanyTestCase) ...
Adding 2016-10-10 17:01:16.559332 to the database.
Extracting 2016-10-10 17:01:16.559000+00:00 from the database.
FAIL
断言错误是:
Traceback (most recent call last):
File "/Users/erip/Code/proj/tests/test_foo_misc.py", line 336, in test_set_foo_start_time
self.assertEqual(t, time)
AssertionError: datet[36 chars], 559332) != datet[36 chars], 559000, tzinfo=<bson.tz_util.FixedOffset obj[15 chars]240>)
为什么存储和提取的时间存在差异?我可以添加一个增量来检查一段时间,但我更愿意存储确切的时间。如何解决这些微秒差异?
答案 0 :(得分:2)
根据BSON spec,日期精度限制为毫秒(强调我的),
UTC datetime - 自Unix时代以来,int64是UTC 毫秒。
有几种不同的方法可以解决这个问题,但这在很大程度上取决于您是否需要亚毫秒精度。如果不这样做,那么你可以在毫秒级舍入或截断:
datetime.datetime.utcnow().replace(microsecond=0)
您还希望确保没有携带的时区信息(因为这会影响您的平等检查)。
如果你需要亚毫秒精度,你可以
存储可在查询时解析的字符串编码时间戳。
datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S.%f")
好处是保持精确度。
这里明显的缺点是字符串仅限于词典排序,这增加了插入前和查询后的另一个步骤。
存储包含时间戳的long或double。
t = datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)
milli = t.total_seconds() * 1000 # microseconds present here
好处是保持精确度,现在可以正确排序。
缺点是你有一个额外的处理步骤。
将日期存储为包含时间戳的字典,作为BSON UTC日期时间(毫秒)加上亚毫秒作为双倍或长
dt = datetime.datetime.utcnow()
t = {
"utc": dt,
"micro": dt.microsecond
}
优点是你已经保持精确度并且可以(索引和)对两个字段进行排序。
缺点是处理步骤和解构时间对象。