BeWithYou

胡搞的技术博客

  1. 首页
  2. 运维/工具
  3. mongoDB时间timezone问题

mongoDB时间timezone问题


之前有个工具性质的内部系统,为了尝尝鲜,我选择了用mongo作为数据库。中间踩过不少坑,后来整理了一个PPT做了次内部分享。结果就没几个人来听…… 尴尬

今天发现了个有关时间的问题,记录一下。

之前我们记录时间用的是unix时间戳,后来想用按日期分组的功能,发现比较困难。因为mongo里关于日期的分组函数都是基于ISODate型数据的。看起来是这样的:

db.getCollection("my_c").insert({'time':new Date()});
//output
{
    "_id" : ObjectId("56d6615170c7fb93c6a6d518"),
    "time" : ISODate("2016-03-02T03:43:13.649Z")
}

一开始看到time字段的值的时候以为数据有问题,比本地时间晚了8个小时,自然联想到时区。其实数据本身没有问题,只是他展现的时候是按照格林尼治时间来的,底层的unix时间戳是正确的。

另外用PHP插入记录的写法是这样的:

db->my_c->insert(array('time'=>new MongoDate()));

PHP里与ISODate对应的是MongoDate类,直接插入即可。需要取时间戳的时候可用$row['time']->sec来获得秒数(非毫秒数)。

这里遇到的问题是我们需要按day来group统计,但是mongo里的dayOfMonth方法计算的实际上是0时区的日期,与我们期望的不符。这里需要修改成下面的写法,手动加上8个小时。

$db->my_c->aggregate([
{
    $match: '....'//省略
},
{
    $project: {
        _id: 0,
        day: { 
            $dayOfMonth : {
                $add : {
                    '$time' : 3600 * 1000 * 8
                }
            } 
        },
    }
},
{
    $group: {
        _id: '$day',
        num : {
            $count: 1
        }
    }
}
]);

上面代码无责任手敲的,没有验证。用$add操作符,手动加了8小时,注意这里是要计算毫秒的。

回到顶部