在MongoDB中汇总当地时区

我正在build设将在意大利使用的mongodb和nodejs应用程序。 意大利时区为+02:00。 这意味着如果有人在7月11日凌晨1点保存一些数据,那么它将被保存为7月10日晚上11点,因为mongo以UTC保存date。 我们需要显示明智的tx计数。 所以我通过查询date进行了分组。 但它显示前一天的TX。 什么应该是这个解决方法。

> db.txs.insert({txid:"1",date : new Date("2015-07-11T01:00:00+02:00")}) > db.txs.insert({txid:"2",date : new Date("2015-07-11T05:00:00+02:00")}) > db.txs.insert({txid:"3",date : new Date("2015-07-10T21:00:00+02:00")}) > db.txs.find().pretty() { "_id" : ObjectId("55a0a55499c6740f3dfe14e4"), "txid" : "1", "date" : ISODate("2015-07-10T23:00:00Z") } { "_id" : ObjectId("55a0a55599c6740f3dfe14e5"), "txid" : "2", "date" : ISODate("2015-07-11T03:00:00Z") } { "_id" : ObjectId("55a0a55699c6740f3dfe14e6"), "txid" : "3", "date" : ISODate("2015-07-10T19:00:00Z") } > db.txs.aggregate([ { $group:{ _id: { day:{$dayOfMonth:"$date"}, month:{$month:"$date"}, year:{$year:"$date"} }, count:{$sum:1} }} ]) { "_id" : { "day" : 11, "month" : 7, "year" : 2015 }, "count" : 1 } { "_id" : { "day" : 10, "month" : 7, "year" : 2015 }, "count" : 2 } 

7月10日和7月11日有2个点。 但是我们需要在七月十一日和七月十日分别显示2 txs和1 tx。

实际上是7月11日在意大利的时候

 db.txs.insert({txid:"1",date : new Date("2015-07-11T01:00:00+02:00")}) 

发生了但mongo存储date为:

 ISODate("2015-07-10T23:00:00Z") 

处理时区是一个“客户端”问题,所以你应该通过时区偏移量来修改“查询”时间,以便在UI等中进行“本地”时间select。 用户界面显示的情况也是如此,其中date将在当地时间表示。

这同样适用于你的集结原则。 只需调整时区偏移。 应用datemath,而不是使用date聚合操作符:

 var tzOffset = 2; db.txs.aggregate([ { "$group": { "_id": { "$subtract": [ { "$add": [ { "$subtract": [ "$date", new Date("1970-01-01") ] }, tzOffset * 1000 * 60 * 60 ]}, { "$mod": [ { "$add": [ { "$subtract": [ "$date", new Date("1970-01-01") ] }, tzOffset * 1000 * 60 * 60 ]}, 1000 * 60 * 60 * 24 ]} ] }, "count": { "$sum": 1 } }} ]).forEach(function(doc){ printjson({ "_id": new Date(doc._id), "count": doc.count }) }); 

哪个给你:

 { "_id" : ISODate("2015-07-10T00:00:00Z"), "count" : 1 } { "_id" : ISODate("2015-07-11T00:00:00Z"), "count" : 2 } 

所以,当你从另一个BSON中$subtract一个date时,结果就是unix时代以来的毫秒数。 只需再次通过“添加”“时区偏移量”来正确调整这一点,这个“时区偏移”可能是正向小时或负向正在背后,再次从时间值转换为有效的毫秒。

四舍五入然后是一个简单的模$mod从“一天中的毫秒数”中获得余数,并删除该数字以仅将调整date舍去到当天。

由于所有的语言库“Date”对象都是以纪元的毫秒(或秒)作为构造函数的参数,所以这里的结果数值很容易被重新转换回date。

所以再次,这是关于修改从“客户”的“本地”呈现的数据响应,而不是关于如何存储数据。 如果您希望在您的应用程序中使用真正的本地化,那么您可以对各处的时区偏移进行修改,如上所述。

其实你可以在聚合框架中自己创builddate,再加上一些datemath。 只需将时代date添加回转换后的date即可:

 db.txs.aggregate([ { "$group": { "_id": { "$add": [ { "$subtract": [ { "$add": [ { "$subtract": [ "$date", new Date(0) ] }, tzOffset * 1000 * 60 * 60 ]}, { "$mod": [ { "$add": [ { "$subtract": [ "$date", new Date(0) ] }, tzOffset * 1000 * 60 * 60 ]}, 1000 * 60 * 60 * 24 ]} ]}, new Date(0); ] }, "count": { "$sum": 1 } }} ])