MongoDB聚合运算符:$dateDiff

$dateDiff聚合运算符返回两个日期只差。

语法

{
   $dateDiff: {
      startDate: <Expression>,
      endDate: <Expression>,
      unit: <Expression>,
      timezone: <tzExpression>,
      startOfWeek: <String>
   }
}

结束日期endDate减去开始日期startDate,返回指定时间单位unit的整数。

参数字段说明:

|字段|是否必须|描述|
|-|-|
|startDate|是|开始时间,可以是任何合法的日期、时间戳或ObjectID表达式|
|startDate|是|结束时间,可以是任何合法的日期、时间戳或ObjectID表达式|
|unit|是|时间单位,可以是结果为yearquarterweekmonthdayhourminutesecondmillisecond的表达式|
|timezone|否|执行操作的时区,<tzExpression>必须是能被解析为奥尔森时区标识符格式的字符串或UTC偏移量,如果timezone不指定,返回值显示为UTC|
|startOfWeek|否|当单位unitweek时使用,默认为星期日,可以是结果为monday (or mon)tuesday (or tue)wednesday (or wed)thursday (or thu)friday (or fri)saturday (or sat)sunday (or sun)之一的字符串表达式|

使用

没有小数单位

$dateDiff表达式返回以指定单位计算的开始日期和结束日期之间的整数差,持续时间是通过计算通过单位边界的次数来确定的,例如,相差 18 个月的两个日期将返回1年的差值,而不是1.5年。

周的开始

除非通过参数startOfWeek指定,否则一周的开始日期为周日。在指定日期的开始日期和结束日期之间开始的任何一周都会被计算在内。周计数不受日历月或日历年的限制。

时区

<timezone>字段中使用 Olson 时区标识符时,MongoDB 会应用 DST 偏移(如果适用于指定的时区)。

例如,包含以下文件的sales集合:

{
   "_id" : 1,
   "item" : "abc",
   "price" : 20,
   "quantity" : 5,
   "date" : ISODate("2017-05-20T10:24:51.303Z")
}

下面的聚合说明了 MongoDB 如何处理 Olson 时区标识符的 DST 偏移量。示例使用$hour$minute操作符返回日期字段的相应部分:

db.sales.aggregate([
{
   $project: {
      "nycHour": {
         $hour: { date: "$date", timezone: "-05:00" }
       },
       "nycMinute": {
          $minute: { date: "$date", timezone: "-05:00" }
       },
       "gmtHour": {
          $hour: { date: "$date", timezone: "GMT" }
       },
       "gmtMinute": {
          $minute: { date: "$date", timezone: "GMT" } },
       "nycOlsonHour": {
          $hour: { date: "$date", timezone: "America/New_York" }
       },
       "nycOlsonMinute": {
          $minute: { date: "$date", timezone: "America/New_York" }
       }
   }
}])

操作返回以下结果:

{
   "_id": 1,
   "nycHour" : 5,
   "nycMinute" : 24,
   "gmtHour" : 10,
   "gmtMinute" : 24,
   "nycOlsonHour" : 6,
   "nycOlsonMinute" : 24
}

其它细节

该算法使用公历计算日期差异。闰年和夏令时计算在内,但不包括闰秒。返回的差值可以是负数。

举例

持续时间

创建一个消费订单集合:

db.orders.insertMany(
   [
      {
         custId: 456,
         purchased: ISODate("2020-12-31"),
         delivered: ISODate("2021-01-05")
      },
      {
         custId: 457,
         purchased: ISODate("2021-02-28"),
         delivered: ISODate("2021-03-07")
      },
      {
         custId: 458,
         purchased: ISODate("2021-02-16"),
         delivered: ISODate("2021-02-18")
      }
   ]
)

在下面的例子中:

  • 返回平均交货天数
  • 使用dateDiff计算购买日期和交货日期之间的天数
 db.orders.aggregate(
    [
       {
          $group:
             {
                 _id: null,
                 averageTime:
                    {
                       $avg:
                          {
                             $dateDiff:
                                {
                                    startDate: "$purchased",
                                    endDate: "$delivered",
                                    unit: "day"
                                }
                           }
                    }
             }
       },
       {
          $project:
             {
                _id: 0,
                numDays:
                   {
                      $trunc:
                         [ "$averageTime", 1 ]
                   }
             }
        }
    ]
)

$group阶段中的$avg累加器使用每个文档上的$dateDiff来获取购买日期和交付日期之间的时间。得出的值将作为averageTime返回。

平均时间的小数部分会在$project阶段被截断 ($trunc),从而产生类似这样的输出结果:

{ "numDays" : 4.6 }

结果精度

创建subscriptions集合,其中包含订阅的开始日期和结束日期:

db.subscriptions.insertMany(
   [
      {
         custId: 456,
         start: ISODate("2010-01-01"),
         end: ISODate("2011-01-01")
      },
      {
         custId: 457,
         start: ISODate("2010-01-01"),
         end: ISODate("2011-06-31")
      },
      {
         custId: 458,
         start: ISODate("2010-03-01"),
         end: ISODate("2010-04-30")
      }
   ]
)

$dateDiff表达式返回以整数单位表示的时间差,单位中没有小数部分。例如,以年为单位计算时,就没有半年。

在本例中,请注意单位的改变对返回精度的影响:

db.subscriptions.aggregate(
   [
      {
         $project:
            {
               Start: "$start",
               End: "$end",
               years:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "year"
                        }
                  },
               months:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "month"
                        }
                  },
               days:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "day"
                        }
                  },
               _id: 0
            }
       }
   ]
 )

结果汇总如下表所示:

StartEndYearsMonthsDays
2010-01-012011-01-01112365
2010-01-012011-07-01118546
2010-03-012010-04-300160

计数只在新单位开始时递增,因此第二行中的18个月为1年,第三行中的60天为1个月。

每月周数

创建一个months集合:

db.months.insertMany(
     [
        {
           month: "January",
           start: ISODate("2021-01-01"),
           end: ISODate("2021-01-31")
        },
        {
           month: "February",
           start: ISODate("2021-02-01"),
           end: ISODate("2021-02-28")
        },
        {
           month: "March",
           start: ISODate("2021-03-01"),
           end: ISODate("2021-03-31")
        },
     ]
   )

可以使用以下代码更改每周的开始时间,并计算出每月的周数:

db.months.aggregate(
   [
      {
         $project:
            {
               wks_default:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "week"
                        }
                  },
               wks_monday:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "week",
                           startOfWeek: "Monday"
                        }
                  },
               wks_friday:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "week",
                           startOfWeek: "fri"
                        }
                  },
               _id: 0
            }
       }
   ]
 )

下表对结果进行了汇总:

MonthSundayMondayFriday
January544
February434
March444

从结果来看:

  • 当 "周初 "是周日时,2021年1月的第5周从31日开始。
  • 由于31日是周日,且位于开始日期和结束日期之间,因此计数会增加一周。
  • 即使日历周在结束日期之后或在下一个日历期间结束,周计数也会递增。
  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

原子星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值