如何在不同的时区按年 - 月 - 日汇总

时间:2013-09-17 14:04:17

标签: mongodb mongo-java

我有一个以UTC格式存储日期对象的MongoDB。好吧,我想在不同的时区(CET)按年,月份进行汇总。

这样做,适用于UTC:

    BasicDBObject group_id = new BasicDBObject("_id", new BasicDBObject("year", new BasicDBObject("$year", "$tDate")).
                append("month", new BasicDBObject("$month", "$tDate")).
                append("day", new BasicDBObject("$dayOfMonth", "$tDate")).
                append("customer", "$customer"));

    BasicDBObject groupFields = group_id.
            append("eventCnt", new BasicDBObject("$sum", "$eventCnt")); 

    BasicDBObject group = new BasicDBObject("$group", groupFields);

或者,如果您使用命令行(未经测试,我只测试了java版本):

{
    $group: {
        _id: {
            "year": {
                "$year", "$tDate"
            },
            "month": {
                "$month", "$tDate"
            },
            "day": {
                "$dayOfMonth", "$tDate"
            },
            "customer": "$customer"
        },
        "eventCount": {
            "$sum": "$eventCount"
        }
    }
}

如何在聚合框架内将这些日期转换为CET?

例如'2013-09-16 23:45:00 UTC'是'2013-09-17 00:45:00 CET',这是另一天。

8 个答案:

答案 0 :(得分:15)

我不是CET及其与UTC的关系的专家,但以下代码(对于shell)应该对MongoDB日期类型进行适当的转换(添加一小时):

db.dates.aggregate(
  {$project: {"tDate":{$add: ["$tDate", 60*60*1000]}, "eventCount":1, "customer":1}}
)

如果在管道的其余部分之前运行该项目命令,则结果应该在CET中。

答案 1 :(得分:7)

搜索了几个小时后,这个解决方案对我有用。它也很简单。只需通过减去时区偏移量(以毫秒为单位)来转换时区。

25200000 = 7小时偏移// 420分钟* 60秒* 1000毫米

$group: {
    _id = { 
        year: { $year : [{ $subtract: [ "$timestamp", 25200000 ]}] }, 
        month: { $month : [{ $subtract: [ "$timestamp", 25200000 ]}] }, 
        day: { $dayOfMonth : [{ $subtract: [ "$timestamp", 25200000 ]}] }
    },
    count = { 
        $sum : 1
    }
};

答案 2 :(得分:6)

您可以将timezone提供给从3.6开始的日期运算符。

用您的时区替换时区。

{
  "$group":{
    "_id":{
      "year":{"$year":{"date":"$tDate","timezone":"America/Chicago"}},
      "month":{"$month":{"date":"$tDate","timezone":"America/Chicago"}},
      "dayOfMonth":{"$dayOfMonth":{"date":"$tDate","timezone":"America/Chicago"}}
    },
    "count":{"$sum":1}
  }
}

答案 3 :(得分:4)

使用例如moment.js来确定CET的当前时区偏移量,但这样可以获得夏季和冬季偏移量

var offsetCETmillisec = moment.tz.zone('Europe/Berlin').offset(moment())* 60 * 1000;

  $group: {
    _id: {
      'year': {'$year': [{ $subtract: [ '$createdAt', offsetCETmillisec ]}] },
      'month': {'$month': [{ $subtract: [ '$createdAt', offsetCETmillisec ]}] },
      'day': {'$dayOfMonth': [{ $subtract: [ '$createdAt', offsetCETmillisec ]}] }
    },
    count: {$sum: 1}
  }
}

答案 4 :(得分:2)

MongoDB's documentation suggests您将时区偏移与时间戳保存在一起:

var now = new Date();
db.data.save( { date: now,
                offset: now.getTimezoneOffset() } );

这当然不是理想的解决方案 - 但是一个有效的解决方案,直到我们在MongoDb的聚合管道中有一个合适的$ utcOffset函数。

答案 5 :(得分:0)

使用时区的解决方案是一个很好的解决方案,但是在3.6版中,您也可以使用时区格式化输出,因此,您可以使用该结果了:

{
"$project":{
    "year_month_day": {"$dateToString": { "format": "%Y-%m-%d", "date": "$tDate", "timezone": "America/Chicago"}}
},
"$group":{
    "_id": "$year_month_day",
    "count":{"$sum":1}
}
}

请确保您的“ $ match”也考虑时区,否则您将得到错误的结果。

答案 6 :(得分:0)

Mongo将日期存储在UTC中, 所以这是将它们带到其他区域的步骤

  • 检查mongo是否将日期保存为UTC,插入一些记录等。
  • 使用moment-timezone.js获取时区偏移量,例如,您的moment()。tz('Europe / Zagreb')。utcOffset()函数 指定的时区
  • 为$ match阶段准备$ gte和$ lte(例如,用户输入日期为1.1.2019-13.1.2019。):
    • 如果offset为正,则在$ match阶段减去(秒);如果offset为负,则add()在$ match阶段的秒数
  • 然后将日期归一化(因为$ match阶段会将它们返回UTC),如下所示: -如果时区偏移量为正,则add()在$ project阶段的秒数; -如果时区偏移量为负,则在$ project阶段减去这些秒。
  • $ group走到最后,这很重要(因为我们要对归一化的结果进行分组,而不是$ match-ed)

基本上是这样的:将输入移至$ match(UTC),然后归一化为您的时区。

答案 7 :(得分:-9)

<?php
    date_default_timezone_set('Asia/Karachi');
    $date=getdate(date("U"));
    $day = $date['mday'];
    $month =$date['mon'];
    $year = $date['year'];
    $currentDate = $year.'-'.$month.'-'.$day;
?>