$dateDiff (aggregation)

On this page本页内容

Definition定义

$dateDiff

New in version 5.0.在版本5.0中新增

Returns the difference between two dates.返回两个日期之间的差值。

The $dateDiff expression has this syntax:$dateDiff表达式具有以下语法:

{
   $dateDiff: {

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

Subtracts startDate from endDate. endDate中减去startDateReturns an integer in the specified unit.返回指定unit的整数。

Field字段Required/Optional必需/可选Description描述
startDateRequired必需The start of the time period. 时间段的开始。The startDate can be any expression that resolves to a Date, a Timestamp, or an ObjectID.startDate可以是解析为日期时间戳ObjectID的任何表达式
endDateRequired必需The end of the time period. 时间段的结束。The endDate can be any expression that resolves to a Date, a Timestamp, or an ObjectID.endDate可以是解析为日期时间戳ObjectID的任何表达式
unitRequired必需

The time measurement unit between the startDate and endDate. startDateendDate之间的时间度量单位。It is an expression that resolves to a string:它是解析为以下字符串的表达式

  • year
  • quarter
  • week
  • month
  • day
  • hour
  • minute
  • second
  • millisecond
timezoneOptional可选

The timezone to carry out the operation. 执行操作的时区。<tzExpression> must be a valid expression that resolves to a string formatted as either an Olson Timezone Identifier or a UTC Offset. 必须是解析为格式为Olson时区标识符UTC偏移量的字符串的有效表达式If no timezone is provided, the result is displayed in UTC.如果未提供timezone,结果将以UTC显示。

Format总体安排Examples示例
Olson Timezone Identifier奥尔森时区标识符
"America/New_York"
"Europe/London"
"GMT"
UTC Offset
+/-[hh]:[mm], e.g. "+04:45"
+/-[hh][mm], e.g. "-0530"
+/-[hh], e.g. "+03"
startOfWeekOptional可选

Used when the unit is equal to week. 当单位等于week时使用。Defaults to Sunday. 默认为SundayThe startOfWeek parameter is an expression that resolves to a case insensitive string:startOfWeek参数是解析为以下不区分大小写字符串的表达式

  • monday (or mon)
  • tuesday (or tue)
  • wednesday (or wed)
  • thursday (or thu)
  • friday (or fri)
  • saturday (or sat)
  • sunday (or sun)
Tip提示
See also: 参阅:

Behavior行为

No Fractional Units无分数单位

The $dateDiff expression returns the integer difference between the startDate and endDate measured in the specified units. $dateDiff表达式返回以指定单位度量的startDateendDate之间的整数差。Durations are measured by counting the number of times a unit boundary is passed. 持续时间是通过计算单位边界通过的次数来衡量的。For example, two dates that are 18 months apart would return 1 year difference instead of 1.5 years.例如,两个相隔18个月的日期将返回1年的差异,而不是1.5年。

Start Of Week周的开始

The start of the week is Sunday unless modified by the startOfWeek parameter. 除非通过startOfWeek参数进行修改,否则一周的开始时间为周日。Any week that begins between the startDate and endDate on the specified day will be counted. 从指定日期的startDateendDate之间开始的任何一周都将被计算在内。The week count is not bounded by calendar month or calendar year.周计数不受日历月或日历年的限制。

Time Zone时区

When using an Olson Timezone Identifier in the <timezone> field, MongoDB applies the DST offset if applicable for the specified timezone.<Timezone>字段中使用Olson时区标识符时,MongoDB将应用DST偏移量(如果适用于指定的时区)。

For example, consider a sales collection with the following document:例如,考虑包含以下文档的sales集合:

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

The following aggregation illustrates how MongoDB handles the DST offset for the Olson Timezone Identifier. 以下聚合说明了MongoDB如何处理Olson时区标识符的DST偏移量。The example uses the $hour and $minute operators to return the corresponding portions of the date field:该示例使用$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" }
       }
   }
}])

The operation returns the following result:该操作返回以下结果:

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

Additional Details其他详细信息

The algorithm calculates the date difference using the Gregorian calendar.该算法使用公历计算日期差。

Leap years and daylight savings time are accounted for but not leap seconds.闰年和夏令时被计算在内,但不包括闰秒。

The difference returned can be negative.返回的差值可以是负数。

Examples示例

Elapsed Time已用时间

Create a collection of customer orders:创建客户订单集合:

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")
      }
   ]
)

The following example:以下示例:

  • Returns the average number of days for a delivery.返回交货的平均天数。
  • Uses dateDiff to calculate the difference between the purchased date and the delivered date.使用dateDiff计算purchased(购买)日期和delivered(交付)日期之间的差异。
 db.orders.aggregate(
    [
       {
          $group:
             {
                 _id: null,
                  averageTime:
                    {
                       $avg:
                          {
                             $dateDiff:
                                {
                                    startDate: "$purchased",
                                     endDate: "$delivered",
                                     unit: "day"
                                }
                           }
                    }
             }
       },
        {
          $project:
             {
                _id: 0,
                 numDays:
                   {
                      $trunc:
                         [ "$averageTime", 1 ]
                   }
             }
        }
    ]
)

The $avg accumulator in the $group stage uses $dateDiff on each document to get the time between the purchased and delivered dates. $group阶段中的$avg累加器在每个文档上使用$dateDiff来获取购买日期和交付日期之间的时间。The resulting value is returned as averageTime.结果值作为averageTime返回。

The decimal portion of the averageTime is truncated ($trunc) in the $project stage to produce output like this:averageTime的小数部分在$project阶段被截断($trunc),以生成如下输出:

{ "numDays" : 4.6 }

Result Precision结果精度

Create this collection with starting and ending dates for a subscription.使用订阅的开始和结束日期创建此集合。

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")
      }
   ]
)

The $dateDiff expression returns a time difference expressed in integer units. $dateDiff表达式返回以整数单位表示的时间差。There are no fractional parts of a unit. 一个单位没有小数部分。For example, when counting in years there are no half years.例如,以年计算时,没有半年。

In this example, note how changing the unit changes the returned precision:在本例中,请注意更改unit如何更改返回的精度:

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
            }
       }
   ]
 )

The results are summarized in this table:结果总结如下表所示:

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

The count only increments when a new unit starts, so 18 months are reported as 1 year in the second row and 60 days are reported as one month in the third row.该计数仅在新unit启动时递增,因此第二行中18个月报告为1年,第三行中60天报告为1个月。

Weeks Per Month每月周数

Create a collection of 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")
        },
      ]
   )

You can change the start of each week, and count the resulting number of weeks in each month with the following code:您可以更改每周的开始时间,并使用以下代码计算每月的周数:

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
            }
       }
   ]
 )

The results are summarized in this table:结果总结如下表所示:

MonthSundayMondayFriday
January544
February434
March444

From the results:从结果来看:

  • When the startOfWeek is Sunday, the 5th week in January, 2021 begins on the 31st.startOfWeek是星期天时,第五周是2021年一月份,从31日开始。
  • Because the 31st is a Sunday and it is between startDate and endDate, one week is added to the count.因为31号是星期天,介于startDateendDate之间,所以计数加上一周。
  • The week count is incremented even when a calendar week finishes after endDate or in the next calendar period.即使一个日历周在endDate之后或在下一个日历期间结束,周计数也会增加。
←  $dateAdd (aggregation)$dateFromParts (aggregation) →