Database Manual / Reference / Query Language / Expressions

$dateAdd (aggregation operator)(聚合运算符)

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(). 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.返回Date()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. The unit is an expression that resolves to one of the following strings:用于测量添加到startDate的时间amountunit。该unit是一个解析为以下字符串之一的表达式

  • year
  • quarter
  • week
  • month
  • day
  • hour
  • minute
  • second
  • millisecond
amountRequired必需The number of units added to the startDate. The amount is an expression that resolves to an integer or long. 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.添加到startDateunits数。amount是一个解析为整数或long的表达式。如果该值可以转换为long而不损失精度,则该金额也可以解析为整数小数或双精度。
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. 执行操作的时区。<tzExpression>必须是解析为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 OffsetUTC偏移
+/-[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. The dateAdd expression always takes a startDate in UTC and returns a result in UTC. If the timezone is specified, the calculation will be done using the specified timezone. The timezone is especially important when a calculation involves Daylight Savings Time (DST).MongoDB遵循以前的数据库使用情况,并使用UTC时间。dateAdd表达式始终采用UTC格式的startDate,并返回UTC格式的结果。如果指定了时区,则将使用指定的时区进行计算。当计算涉及夏令时(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.如果unitmonth或更大,则操作将调整为考虑该月的最后一天。例如,在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集合:

 db.sales.insertOne(
{
"_id" : 1,
"item" : "abc",
"price" : 10,
"quantity" : 2,
"date" : ISODate("2014-01-01T08:15:39.736Z")
}
)

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阶段将使用expectedDeliveryDate更新原始文档。

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来比较实际交付日期和预期日期。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 returns the date in ISODate format and assumes a UTC timezone.如果不进行转换,MongoDB将以ISODate格式返回日期,并假定为UTC时区。

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.首先在每个文档的login日期中添加1天,然后添加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 York纽约Mexico 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. The $login for New York is UTC -5, however the start, days, and hours rows display the time in UTC.未格式化的日期以UTC返回。纽约的$login是UTC -5,但startdayshours行显示的是UTC时间。
  • March 14th is the start of DST in New York, but not in Mexico. The calculated time is adjusted when a location switches to DST and crosses from one day to the next.3月14日是纽约夏令时的开始,但墨西哥不是。当一个地点切换到夏令时并从一天跨越到下一天时,计算的时间会进行调整。
  • 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.夏令时修改的是一天的长度,而不是小时。几个小时没有夏令时变化。只有当测量单位为天或更大,并且计算跨越指定时区的时钟变化时,才会对夏令时进行调整。