How to aggregate by year-month-day on a different timezone

后端 未结 8 1652
无人及你
无人及你 2020-11-29 02:21

I have a MongoDB whom store the date objects in UTC. Well, I want to perform aggregation by year,month day in a different timezone (CET).

doing this, works fine for

相关标签:
8条回答
  • 2020-11-29 02:53

    You can provide the timezone to the date operators starting in 3.6.

    Replace the timezone with your timezone.

    {
      "$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}
      }
    }
    
    0 讨论(0)
  • 2020-11-29 02:54

    After searching for hours, this is the solution that worked for me. It is also very simple. Just convert the timezone by subtracting the timezone offset in milliseconds.

    25200000 = 7 hour offset // 420 min * 60 sec * 1000 mili

    $group: {
        _id = { 
            year: { $year : [{ $subtract: [ "$timestamp", 25200000 ]}] }, 
            month: { $month : [{ $subtract: [ "$timestamp", 25200000 ]}] }, 
            day: { $dayOfMonth : [{ $subtract: [ "$timestamp", 25200000 ]}] }
        },
        count = { 
            $sum : 1
        }
    };
    
    0 讨论(0)
  • 2020-11-29 03:00

    The solution with timezone is a good one, but in version 3.6 you can also format the output using timezone, so, you get the result ready for use:

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

    Make sure that your "$match" also considers timezone, or else you will get wrong results.

    0 讨论(0)
  • 2020-11-29 03:00

    Mongo stores the dates in UTC, so this is the procedure to get them in other zone

    • check that mongo saves the dates in UTC, insert some records etc.
    • get timezone offset with moment-timezone.js eg moment().tz('Europe/Zagreb').utcOffset() functions, for your specified timezone
    • Prepare $gte and $lte for $match stage (eg user input for dates 1.1.2019 - 13.1.2019.):
      • If offset is positive subtract() those seconds in $match stage; If offset is negative add() those seconds in $match stage
    • Then normalize the dates (because $match stage will return them in UTC) to your zone like this: -if timezone offset is positive add() those seconds in $project stage; -if timezone offset is negative subtract() those seconds in $project stage.
    • $group goes last, this is important (because we want to group normalized results, and not $match-ed)

    Basically it is this: shift input(s) to $match(UTC), and then normalize to your timezone.

    0 讨论(0)
  • 2020-11-29 03:03

    I'm not an expert on CET and its relation to UTC, but the following code (for the shell) should do a proper conversion (adding an hour) to a MongoDB date type:

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

    If you run that project command before the rest of your pipeline, the results should be in CET.

    0 讨论(0)
  • 2020-11-29 03:03

    MongoDB's documentation suggests that you save the timezone offset alongside the timestamp:

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

    This is of course not the ideal solution – but one that works, until we have in MongoDb's aggregation pipeline a proper $utcOffset function.

    0 讨论(0)
提交回复
热议问题