$dateDiff(聚合)
定义
$dateDiff
版本 5.0 中的新增功能。
返回两个日期之间的差值。
$dateDiff
表达式的语法如下:{ $dateDiff: { startDate: <Expression>, endDate: <Expression>, unit: <Expression>, timezone: <tzExpression>, startOfWeek: <String> } } 从
endDate
中减去startDate
。返回指定unit
中的整数。字段必需/可选说明startDate
必需endDate
必需unit
必需startDate
和endDate
之间的时间测量单位 (unit
)。它是一个解析为字符串的表达式:year
quarter
week
month
day
hour
minute
second
millisecond
timezone
Optional执行操作的时区。
<tzExpression>
必须是有效 表达式 string,可解析为格式为 Olson 时区标识符 的 或 UTC 偏移量 。如果未提供timezone
,则结果将显示在UTC
中。format示例Olson 时区标识符"America/New_York" "Europe/London" "GMT" UTC 偏移+/-[hh]:[mm], e.g. "+04:45" +/-[hh][mm], e.g. "-0530" +/-[hh], e.g. "+03" startOfWeek
Optional当单位等于
week
时使用。默认为Sunday
。startOfWeek
参数是一个解析为不区分大小写的字符串的表达式:monday
(或mon
)tuesday
(或tue
)wednesday
(或wed
)thursday
(或thu
)friday
(或fri
)saturday
(或sat
)sunday
(或sun
)
行为
无小数单位
$dateDiff
表达式返回指定 units
中测量到的 startDate
和 endDate
之间的整数差。持续时间通过计算单位边界被传递的次数来测量。例如,相隔 18 个月的两个日期将返回 1 year
的差值,而不是 1.5 years
。
一周开始
除非被 startOfWeek
参数修改,否则 week
的起始为 Sunday
。在指定日子所介于的 startDate
和 endDate
之间的任何一周都将计算在内。周计数不受日历 month
或日历 year
限制。
时区
在 <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
操作符返回 date
字段的相应部分:
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
计算purchased
日期和delivered
日期之间的差值。
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
来获取 purchased
和 delivered
日期之间的时间。结果值作为 averageTime
返回。
averageTime
的十进制部分在 $project
阶段被截断 ($trunc
) 以生成如下输出:
{ "numDays" : 4.6 }
结果精度
使用订阅的开始日期和结束日期创建此集合。
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
表达式返回以整数 units
表示的时间差。单位没有小数部分。例如,在计算 years
时,没有半年。
在本例中,请注意更改 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 } } ] )
结果汇总如下表所示:
开始 | End | 年份 | 月数 | 天数 |
---|---|---|---|---|
2010-01-01 | 2011-01-01 | 1 | 12 | 365 |
2010-01-01 | 2011-07-01 | 1 | 18 | 546 |
2010-03-01 | 2010-04-30 | 0 | 1 | 60 |
该计数仅在新的 unit
开始时递增,因此第二行中的 18 个月报告为 1 年,第三行中的 60 天报告为一个月。
每月周数
创建一个月份集合:
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 } } ] )
结果汇总如下表所示:
月 | 星期日 | 星期一 | 星期五 |
---|---|---|---|
一月 | 5 | 4 | 4 |
二月 | 4 | 3 | 4 |
2022 年 | 4 | 4 | 4 |
从结果来看:
当
startOfWeek
是星期日时,2021 年 1 月的第 5 个week
从 31 号开始。由于 31 日是周日,且介于
startDate
和endDate
之间,因此计数时要加上一个week
。即使日历周在
endDate
之后或在下一个日历周期内结束,week
计数也会增加。