使用mongod在utc中存储日期时如何处理时区问题?

Hri*_*shi 31 timezone mongodb mongoid aggregation-framework

我有一个mongodb集合,其中每个文档都有一些属性和一个utc时间戳.我需要从集合中提取数据并使用聚合框架,因为我使用集合中的数据在用户界面上显示一些图表.但是,我需要根据用户的时区进行聚合.假设我知道用户的时区(通过浏览器或其他方式传递请求),有没有办法使用聚合框架根据[客户端]时区进行聚合?

Ast*_*ral 37

除了Matt Johnson提到的SERVER-6310之外,另一个解决方法是使用$project运算符在UTC时区中添加或减去"将时间"转移到正确的本地区域.事实证明,您可以以毫秒为单位添加或减去时间.

例如,假设我有一个名为Date的字段orderTime.我想查询EDT.那是距UTC的-4小时.那是4*60*60*1000毫秒.

所以我会写下面的投影来获取day_ordered我所有记录的当地时间:

db.table.aggregate( 
    { $project : { orderTimeLocal : { $subtract : [ "$orderTime", 14400000] } } },
    { $project : { day_ordered : { $dayOfYear : "$orderTimeLocal" } } })
Run Code Online (Sandbox Code Playgroud)

  • 由于夏令时,这不起作用.偏移量可以是-4或-5,具体取决于日期/月份. (12认同)

Seb*_*ian 16

上面建议的每种方法都可以很好地工作,但是由于有一个新版本的mongodb,你可以$let在聚合框架中使用2.6,这样你就可以动态创建变量,从而避免$project在分组之前的需要.现在,您可以创建一个包含$let本地化时间的变量,并在$group运算符中使用它.

就像是:

db.test.aggregate([
   {$group: { 
        _id: { 
             $let: { 
                 vars: {  
                     local_time: { $subtract: ["$date", 10800000]} 
                 }, 
                 in: { 
                    $concat: [{$substr: [{$year: "$$local_time"}, 0, 4]}, 
                              "-", 
                              {$substr: [{$month: "$$local_time"}, 0, 2]}, 
                              "-", 
                              {$substr: [{$dayOfMonth: "$$local_time"}, 0, 2]}]
                 }
              }
         }, 
         count: {$sum: 1}
     }
 }])
Run Code Online (Sandbox Code Playgroud)

请注意,您使用$let块/变量的内部定义,并且该块/变量的值是子表达式的返回值"in",其中使用了上面定义的变量.

  • 这在涉及夏时制的情况下也不起作用,因为您假定可以减去固定时间,此时正确的值可能会相差一个小时,具体取决于本地时间是否在夏时制中。 (2认同)

Mat*_*int 11

您目前正在MongoDB问题SERVER-6310中讨论您所要求的内容.

我在一个讨论主题的链接中找到了这个.

对于按日期进行的任何分组,这个问题很常见,包括SQL数据库和NoSQL数据库.事实上,我最近在RavenDB中解决了这个问题.有问题,一个解决方案RavenDB一个很好的说明这里.

MongoDB问题讨论了一种解决方法,类似于我在上面的评论中所描述的.您可以预先计算您感兴趣的当地时间,然后按这些时间进行分组.

用这两种方法很难覆盖世界上的每个时区.您应该决定对您的用户群有意义的少数目标区域,例如我在RavenDB文章中描述的每个办公室方法.

更新:此问题已于2017年7月在MongoDB中解决(版本3.5.11). 解决方案在上面的第一个链接中描述,但简而言之,它们为聚合表达式中的日期引入了一种新的对象格式:{ date: <dateExpression>, timezone: <tzExpression> }允许您指定聚合时使用的时区.请参阅此处以获取Mongo文档中的另一个示例.