为什么使用PyMongo客户端在Mongo数据库中存储和查询时间之间存在差异?

时间:2016-10-10 16:53:59

标签: mongodb python-3.x datetime pymongo

我有一个带有foo个对象的MongoDB数据库。我想记录它们添加到数据库的时间。为此,我的方法是存储时间,将foo添加到数据库并设置开始时间。当我从数据库中获取foo时,开始时间属性应该与我添加它的时间相匹配。

以下是我的测试,反映了这一点。这些功能并不十分重要,因为它们基本上是db.collection.insertdb.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>)

为什么存储和提取的时间存在差异?我可以添加一个增量来检查一段时间,但我更愿意存储确切的时间。如何解决这些微秒差异?

1 个答案:

答案 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
    }
    

    优点是你已经保持精确度并且可以(索引和)对两个字段进行排序。

    缺点是处理步骤和解构时间对象。