Docs HomeMongoDB Manual

$dateAdd (aggregation)

Definition定义

$dateAdd

New in version 5.0. 5.0版新增。

Increments a Date() object by a specified number of time units.Date()对象增加指定数量的时间单位。

The $dateAdd expression has the following syntax:$dateAdd表达式具有以下语法:

{
$dateAdd: {
startDate: <Expression>,
unit: <Expression>,
amount: <Expression>,
timezone: <tzExpression>
}
}

Returns a Date(). 返回Date()The startDate can be any expression that resolves to type Date, Timestamp or ObjectId. No matter which data type is used as input, the value returned will be a Date() object.startDate可以是解析为DateTimestampObjectId类型的任何表达式。无论使用哪种数据类型作为输入,返回的值都将是Date()对象。

Field字段Required/Optional必需/可选Description描述
startDateRequired必要的The beginning date, in UTC, for the addition operation. 添加操作的开始日期,以UTC为单位。The startDate can be any expression that resolves to a Date, a Timestamp, or an ObjectID.startDate可以是解析为DateTimestampObjectID的任何表达式
unitRequired必要的The unit used to measure the amount of time added to the startDate. 用于测量添加到startDate的时间amountunitThe unit is an expression that resolves to one of the following strings: unit是一个解析为以下字符串之一的表达式
  • year
  • quarter
  • week
  • month
  • day
  • hour
  • minute
  • second
  • millisecond
amountRequired必要的The number of units added to the startDate. 添加到startDateunits数。The amount is an expression that resolves to an integer or long. amount是一个解析为整数或长的表达式The amount can also resolve to an integral decimal or a double if that value can be converted to a long without loss of precision.如果可以在不损失精度的情况下将该值转换为长,则amount也可以解析为小数点整数或双精度。
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 IdentifierOlson时区标识符
"America/New_York"
"Europe/London"
"GMT"
UTC Offset
+/-[hh]:[mm], e.g. "+04:45"
+/-[hh][mm], e.g. "-0530"
+/-[hh], e.g. "+03"

For more information on expressions and types see Expressions and BSON Types.有关表达式和类型的详细信息,请参阅表达式BSON类型

Behavior行为

Time Measurement时间测量

MongoDB follows prevaling database usage and works with time in UTC. MongoDB遵循普遍使用的数据库,并使用UTC中的时间。The dateAdd expression always takes a startDate in UTC and returns a result in UTC. dateAdd表达式总是以UTC为起始日期,并以UTC为返回结果。If the timezone is specified, the calculation will be done using the specified timezone. 如果指定了timezone,则将使用指定的timezone进行计算。The timezone is especially important when a calculation involves Daylight Savings Time (DST).当计算涉及夏令时(DST)时,时区尤其重要。

If the unit is a month, or larger the operation adjusts to account for the last day of the month. Adding one month on the last day of October, for example, demonstrates the "last-day-of-the-month" adjustment.如果unit是一个月或month,则操作会根据该月的最后一天进行调整。例如,在10月的最后一天加上一个月,就表明了“一个月最后一天”的调整。

{
$dateAdd:
{
startDate: ISODate("2020-10-31T12:10:05Z"),
unit: "month",
amount: 1
}
}

Notice that the date returned, ISODate("2020-11-30T12:10:05Z"), is the 30th and not the 31st since November has fewer days than October.请注意,返回的日期ISODate("2020-11-30T12:10:05Z")是第30天,而不是第31天,因为11月的天数比10月少。

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
}

Examples实例

Add a Future Date添加未来日期

Consider a collection of customer orders with these documents:考虑包含以下文档的客户订单集合:

db.shipping.insertMany(
[
{ custId: 456, purchaseDate: ISODate("2020-12-31") },
{ custId: 457, purchaseDate: ISODate("2021-02-28") },
{ custId: 458, purchaseDate: ISODate("2021-02-26") }
]
)

The normal shipping time is 3 days. You can use $dateAdd in an aggregation pipeline to set an expectedDeliveryDate 3 days in the future.正常运输时间为3天。您可以在聚合管道中使用$dateAdd来设置未来3天的expectedDeliveryDate

db.shipping.aggregate(
[
{
$project:
{
expectedDeliveryDate:
{
$dateAdd:
{
startDate: "$purchaseDate",
unit: "day",
amount: 3
}
}
}
},
{
$merge: "shipping"
}
]
)

After adding 3 days to the purchaseDate with $dateAdd in the $project stage, the $merge stage updates the original documents with the expectedDeliveryDate.$project阶段中使用$dateAddpurchaseDate添加3天后,$merge阶段将使用预期的DeliveryDate更新原始文档。

The resulting documents look like this:生成的文档如下所示:

{
"_id" : ObjectId("603dd4b2044b995ad331c0b2"),
"custId" : 456,
"purchaseDate" : ISODate("2020-12-31T00:00:00Z"),
"expectedDeliveryDate" : ISODate("2021-01-03T00:00:00Z")
}
{
"_id" : ObjectId("603dd4b2044b995ad331c0b3"),
"custId" : 457,
"purchaseDate" : ISODate("2021-02-28T00:00:00Z"),
"expectedDeliveryDate" : ISODate("2021-03-03T00:00:00Z")
}
{
"_id" : ObjectId("603dd4b2044b995ad331c0b4"),
"custId" : 458,
"purchaseDate" : ISODate("2021-02-26T00:00:00Z"),
"expectedDeliveryDate" : ISODate("2021-03-01T00:00:00Z")
}

Filter on a Date Range按日期范围筛选

Update the shipping collection from the last example with this code to add delivery dates to the documents:使用以下代码更新上一个示例中的shipping集合,以便将交货日期添加到文档中:

db.shipping.updateOne(
{ custId: 456 },
{ $set: { deliveryDate: ISODate( "2021-01-10" ) } }
)

db.shipping.updateOne(
{ custId: 457 },
{ $set: { deliveryDate: ISODate( "2021-03-01" ) } }
)

db.shipping.updateOne(
{ custId: 458 },
{ $set: { deliveryDate: ISODate( "2021-03-02" ) } }
)

You want to find late shipments. Use $dateAdd in a $match stage to create a filter that matches documents in a range of dates defined by a starting point ($purchaseDate) and a time period given by $dateAdd.您想查找延迟发货。在$match阶段中使用$dateAdd可以创建一个筛选器,该筛选器匹配由起点($purchaseDate)和$dateAdd给定的时间段定义的日期范围内的文档。

db.shipping.aggregate(
[
{
$match:
{
$expr:
{
$gt:
[ "$deliveryDate",
{
$dateAdd:
{
startDate: "$purchaseDate",
unit: "day",
amount: 5
}
}
]
}
}
},
{
$project:
{
_id: 0,
custId: 1,
purchased:
{
$dateToString:
{
format: "%Y-%m-%d",
date: "$purchaseDate"
}
},
delivery:
{
$dateToString:
{
format: "%Y-%m-%d",
date: "$deliveryDate"
}
}
}
}
]
)

The $match stage uses $gt and $dateAdd in an expression ($expr) to compare the actual deliveryDate with an expected date. $match阶段在表达式($expr)中使用$gt$dateAdd将实际deliveryDate与预期日期进行比较。Documents with delivery dates more than 5 days after the purchaseDate are passed on to the $project stage.交付日期在purchaseDate后5天以上的文档将传递到$project阶段。

The $project stage uses the $dateToString expression to convert the dates to a more readable format. $project阶段使用$dateToString表达式将日期转换为可读性更强的格式。Without the conversion, MongoDB would return the date in ISODate format.如果不进行转换,MongoDB将以ISODate格式返回日期。

In this example only one record is returned:在本例中,只返回一条记录:

{ "custId" : 456, "purchased" : "2020-12-31", "delivery" : "2021-01-10" }

Adjust for Daylight Savings Time夏令时调整

All dates are stored internally in UTC time. When a timezone is specified, $dateAdd uses local time to carry out the calculations. The results are displayed in UTC.所有日期都以UTC时间存储在内部。指定timezone后,$dateAdd将使用本地时间进行计算。结果以UTC显示。

You have customers in several timezones and you want to see what effect daylight savings time might have on your billing periods if you bill by day or by hour.您有几个时区的客户,您想看看如果您按day或按hour计费,夏令时可能会对您的计费周期产生什么影响。

Create this collection of connection times:创建此连接时间集合:

db.billing.insertMany(
[
{
location: "America/New_York",
login: ISODate("2021-03-13T10:00:00-0500"),
logout: ISODate("2021-03-14T18:00:00-0500")
},
{
location: "America/Mexico_City",
login: ISODate("2021-03-13T10:00:00-00:00"),
logout: ISODate("2021-03-14T08:00:00-0500")
}
]
)

First add 1 day, then add 24 hours to the login dates in each document.首先在每个文档中添加1天,然后在login日期上添加24小时。

db.billing.aggregate(
[
{
$project:
{
_id: 0,
location: 1,
start:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date: "$login"
}
},
days:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateAdd:
{
startDate: "$login",
unit: "day",
amount: 1,
timezone: "$location"
}
}
}
},
hours:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateAdd:
{
startDate: "$login",
unit: "hour",
amount: 24,
timezone: "$location"
}
}
}
},
startTZInfo:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date: "$login",
timezone: "$location"
}
},
daysTZInfo:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateAdd:
{
startDate: "$login",
unit: "day",
amount: 1,
timezone: "$location"
}
},
timezone: "$location"
}
},
hoursTZInfo:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateAdd:
{
startDate: "$login",
unit: "hour",
amount: 24,
timezone: "$location"
}
},
timezone: "$location"
}
},
}
}
]
).pretty()

The $dateToString expression reformats the output for readability. Results are summarized here:$dateToString表达式重新格式化输出以提高可读性。结果总结如下:

Field字段New YorkMexico City
Start2021-03-13 15:002021-03-13 10:00
Start, TZ Info2021-03-13 10:002021-03-13 04:00
1 Day2021-03-14 14:002021-03-14 10:00
1 Day, TZ Info2021-03-14 10:002021-03-14 04:00
24 Hours2021-03-14 15:002021-03-14 10:00
24 Hours, TZ Info2021-03-14 11:002021-03-14 04:00

The chart highlights several points:该图表突出显示了以下几点:

  • Unformatted dates are returned in UTC. 未格式化的日期以UTC返回。The $login for New York is UTC -5, however the start, days, and hours rows display the time in UTC.纽约的$login是UTC-5,但是startdayshours行显示UTC时间。
  • March 14th is the start of DST in New York, but not in Mexico. 3月14日是纽约夏令时的开始,但墨西哥没有。The calculated time is adjusted when a location switches to DST and crosses from one day to the next.当位置切换到夏令时并从一天穿越到下一天时,计算的时间会进行调整。
  • DST modifies the length of the day, not the hour. There is no DST change for hours. 夏令时修改的是一天的长度,而不是小时。夏令时在数小时内没有变化。There is an only an adjustment for DST when the measurement unit is day or larger and the computation crosses a clock change in the specified timezone.当测量unitday或更大,并且计算跨越指定时区的时钟变化时,仅对DST进行调整。
Tip

See also: 另请参阅:

$dateSubtract, $dateDiff