日付オブジェクトを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:00UTC」は「2013-09-1700:45:00 CET」ですが、これは別の日です。
私はCETとUTCとの関係の専門家ではありませんが、次のコード(シェル用)は、MongoDB日付型に適切に変換(1時間を追加)する必要があります。
db.dates.aggregate(
{$project: {"tDate":{$add: ["$tDate", 60*60*1000]}, "eventCount":1, "customer":1}}
)
パイプラインの残りの部分の前にそのプロジェクトコマンドを実行すると、結果はCETになります。
時間を検索した後、これは私のために働いた解決策です。それもとても簡単です。ミリ秒単位のタイムゾーンオフセットを減算して、タイムゾーンを変換するだけです。
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
}
};
3.6以降の日付演算子に 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}
}
}
たとえば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}
}
}
MongoDBのドキュメントが示唆している タイムスタンプと一緒にタイムゾーンオフセットを保存すること:
var now = new Date();
db.data.save( { date: now,
offset: now.getTimezoneOffset() } );
もちろん、これは理想的なソリューションではありませんが、MongoDbの集約パイプラインに適切な$ utcOffset関数が含まれるまでは、機能します。
タイムゾーンを使用したソリューションは優れていますが、バージョン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」もタイムゾーンを考慮していることを確認してください。そうしないと、間違った結果が得られます。
Mongoは日付をUTCで保存するため、これは他のゾーンで日付を取得する手順です。
基本的にはこれです:入力を$ match(UTC)にシフトしてから、タイムゾーンに正規化します。