Definición
$dateSubtractNuevo en la versión 5.0.
Disminuye a
Date()objeto por un número específico de unidades de tiempo.El
$dateSubtractLa expresión tiene la siguiente sintaxis:{ $dateSubtract: { startDate: <Expression>, unit: <Expression>, amount: <Expression>, timezone: <tzExpression> } } Devuelve un
Date(). ElstartDatepuede ser cualquier expresión que resuelva el tipo Fecha, Marca de tiempo u ObjectId. Independientemente del tipo de dato utilizado como entrada, el valor devuelto será un objetoDate().CampoObligatorio/OpcionalDescripciónstartDateRequerido
La fecha de inicio, en UTC, de la operación de resta. El
startDatepuede ser cualquier expresión que se resuelva en una fecha, una marca de tiempo o un ID de objeto.unitRequerido
El
unitse utiliza para medir elamountde tiempo restadostartDatedel. Elunites una expresión que se resuelve en una de las siguientes cadenas:yearquarterweekmonthdayhourminutesecondmillisecond
amountRequerido
El número de
unitsrestadostartDatede.amountes una expresión que se resuelve en un entero o long.amounttambién puede resolverse en un decimal entero o double si ese valor se puede convertir a long sin pérdida de precisión.timezoneOpcional
La zona horaria para realizar la operación.
<tzExpression>debe ser una expresión válida que se resuelva en una cadena formateada como un identificador de zona horaria de Olsono una diferencia UTC. Si notimezonese proporciona, el resultado se muestraUTCen.FormatoEjemplosIdentificador de zona horaria de Olson
"America/New_York" "Europe/London" "GMT" Desplazamiento UTC
+/-[hh]:[mm], e.g. "+04:45" +/-[hh][mm], e.g. "-0530" +/-[hh], e.g. "+03" Para obtener más información sobre expresiones y tipos, consulte Expresiones y tipos BSON.
Comportamiento
Medición del tiempo
MongoDB sigue el uso prevalente de bases de datos y trabaja con el tiempo en UTC. La expresión dateSubtract siempre toma un startDate en UTC y devuelve un resultado en UTC. Si se especifica el timezone, el cálculo se realizará utilizando el timezone especificado. La zona horaria es especialmente importante cuando un cálculo implica el horario de verano (DST).
Si unit es month o mayor, la operación se ajusta para tener en cuenta el último día del mes. Restar un month al último día de marzo, por ejemplo, demuestra el ajuste del "último día del mes".
{ $dateSubtract: { startDate: ISODate("2021-03-31T12:10:05Z"), unit: "month", amount: 1 } }
Tenga en cuenta que la fecha devuelta, ISODate("2021-02-28T12:10:05Z"), es la 28y no la 31ya que febrero tiene menos días que marzo.
Zona horaria
Al utilizar un identificador de zona horaria de Olson en el campo <timezone>, MongoDB aplica el Desplazamiento del horario de verano, si corresponde para la zona horaria especificada.
Por ejemplo, considera una colección sales con el siguiente documento:
db.sales.insertOne( { "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-01-01T08:15:39.736Z") } )
La siguiente agregación ilustra cómo MongoDB gestiona la diferencia horaria del identificador de zona horaria Olson. El ejemplo utiliza los operadores $hour y para devolver las partes correspondientes del $minute date campo:
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" } } } }])
La operación devuelve el siguiente resultado:
{ "_id": 1, "nycHour" : 5, "nycMinute" : 24, "gmtHour" : 10, "gmtMinute" : 24, "nycOlsonHour" : 6, "nycOlsonMinute" : 24 }
Ejemplos
Restar una cantidad fija
Considere una colección de tiempos de conexión del sistema como estos:
db.connectionTime.insertMany( [ { custId: 457, login: ISODate("2020-12-25T19:04:00"), logout: ISODate("2020-12-28T09:04:00") }, { custId: 457, login: ISODate("2021-01-27T05:12:00"), logout: ISODate("2021-01-28T13:05:00") }, { custId: 458, login: ISODate("2021-01-22T06:27:00"), logout: ISODate("2021-01-31T11:00:00") }, { custId: 459, login: ISODate("2021-02-14T20:14:00"), logout: ISODate("2021-02-17T16:05:00") }, { custId: 460, login: ISODate("2021-02-26T02:44:00"), logout: ISODate("2021-02-18T14:13:00") } ] )
Debido a un problema de servicio, debe restar 3 horas de cada cierre de sesión de enero 2021. Puede usar $dateSubtract en una secuencia de agregación para restar logoutTime.
db.connectionTime.aggregate( [ { $match: { $expr: { $eq: [ { $year: "$logout" }, 2021 ] }, $expr: { $eq: [ { $month: "$logout" }, 1 ] } } }, { $project: { logoutTime: { $dateSubtract: { startDate: "$logout", unit: "hour", amount: 3 } } } }, { $merge: "connectionTime" } ] )
Se realizan dos comparaciones similares en la etapa$match. Primero, los operadores$yeary$monthextraen el año y el mes, respectivamente, del objeto de fecha logoutTime. A continuación, se comprueba si el mes y el año coinciden con los objetivos de selección. Dado que "enero" se codifica como "1", $expres verdadero cuando el año y el mes son iguales ($eq) a "2021" y "1".
La etapa $project utiliza $dateSubtract para restar 3 horas de las logoutTime de cada documento seleccionado.
Finalmente, la etapa actualiza la colección, escribiendo el $merge nuevo logoutTime para los documentos modificados.
Nota
A diferencia de,$out la $merge etapa solo actualiza los documentos coincidentes y conserva el resto de la colección. Para más detalles, consulte: $out comparado con $merge.
Los documentos resultantes se ven así:
{ "_id" : ObjectId("603dd94b044b995ad331c0b5"), "custId" : 457, "login" : ISODate("2020-12-25T19:04:00Z"), "logout" : ISODate("2020-12-28T09:04:00Z") } { "_id" : ObjectId("603dd94b044b995ad331c0b6"), "custId" : 457, "login" : ISODate("2021-01-27T05:12:00Z"), "logout" : ISODate("2021-01-28T13:05:00Z"), "logoutTime" : ISODate("2021-01-28T10:05:00Z") } { "_id" : ObjectId("603dd94b044b995ad331c0b7"), "custId" : 458, "login" : ISODate("2021-01-22T06:27:00Z"), "logout" : ISODate("2021-01-31T11:00:00Z"), "logoutTime" : ISODate("2021-01-31T08:00:00Z") } { "_id" : ObjectId("603dd94b044b995ad331c0b8"), "custId" : 459, "login" : ISODate("2021-02-14T20:14:00Z"), "logout" : ISODate("2021-02-17T16:05:00Z") } { "_id" : ObjectId("603dd94b044b995ad331c0b9"), "custId" : 460, "login" : ISODate("2021-02-26T02:44:00Z"), "logout" : ISODate("2021-02-18T14:13:00Z") }
Filtrar por fechas relativas
Quiere enviar una encuesta a los clientes que usaron su servicio la semana pasada. La expresión $dateSubtract puede crear un filtro de rango relativo a la hora de ejecución de la consulta.
db.connectionTime.aggregate( [ { $match: { $expr: { $gt: [ "$logoutTime", { $dateSubtract: { startDate: "$$NOW", unit: "week", amount: 1 } } ] } } }, { $project: { _id: 0, custId: 1, loggedOut: { $dateToString: { format: "%Y-%m-%d", date: "$logoutTime" } } } } ] )
La variable de agregación integrada$$NOWdevuelve la fecha y hora actual en formato ISODate. La etapa$matchutiliza el valor de$$NOWpara obtener la fecha actual. A continuación, la expresión de comparación ($expr) filtra la colección utilizando valores mayores que ($gt) y $dateSubtract para encontrar los documentos con un valor de logoutTime en la última semana.
La etapa $project usa la expresión para convertir las fechas a un formato $dateToString más legible. Sin la conversión, MongoDB devolvería la fecha en formato ISODate. El resultado muestra que dos clientes cerraron sesión la semana pasada.
{ "custId" : 459, "loggedOut" : "2021-02-17" } { "custId" : 460, "loggedOut" : "2021-02-18" }
Adaptarse al horario de verano
Todas las fechas se almacenan internamente en hora UTC. Cuando se especifica timezone, $dateSubtract utiliza la hora local para realizar los cálculos. Los resultados se muestran en UTC.
Tiene clientes en varias zonas horarias y desea ver qué efecto podría tener el horario de verano en sus períodos de facturación si factura antes del day o del hour.
Crea esta colección de tiempos de conexión:
db.billing.insertMany( [ { location: "America/New_York", login: ISODate("2021-03-14T10:00:00-0500"), logout: ISODate("2021-03-14T18:00:00-0500") }, { location: "America/Mexico_City", login: ISODate("2021-03-14T10:00:00-00:00"), logout: ISODate("2021-03-15T08:00:00-0500") } ] )
Primero reste 1 día, luego reste 24 horas de las login fechas en cada documento.
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: { $dateSubtract: { startDate: "$login", unit: "day", amount: 1, timezone: "$location" } } } }, hours: { $dateToString: { format: "%Y-%m-%d %H:%M", date: { $dateSubtract: { 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: { $dateSubtract: { startDate: "$login", unit: "day", amount: 1, timezone: "$location" } }, timezone: "$location" } }, hoursTZInfo: { $dateToString: { format: "%Y-%m-%d %H:%M", date: { $dateSubtract: { startDate: "$login", unit: "hour", amount: 24, timezone: "$location" } }, timezone: "$location" } }, } } ] ).pretty()
La expresión reformatea la salida para facilitar su lectura. Los resultados se resumen a $dateToString continuación:
Campo | New York | Ciudad de México |
|---|---|---|
Inicio | 2021-03-14 15:00 | 2021-03-14 15:00 |
Inicio, información de TZ | 2021-03-14 11:00 | 2021-03-14 04:00 |
1 día | 2021-03-13 16:00 | 2021-03-13 15:00 |
1 Día, TZInfo | 2021-03-13 11:00 | 2021-03-13 09:00 |
24 Horas | 2021-03-13 15:00 | 2021-03-13 15:00 |
24 Horas, TZInfo | 2021-03-13 10:00 | 2021-03-13 09:00 |
El gráfico destaca varios puntos:
Las fechas sin formato se muestran en UTC. El
$loginde Nueva York es UTC -5; sin embargo, las filasstart,daysyhoursmuestran la hora en UTC.El 14de marzo marca el inicio del horario de verano en Nueva York, pero no en México. La hora calculada se ajusta cuando una ubicación cambia al horario de verano y pasa de un
daya otro.El horario de verano (DST) modifica la duración de
day, no dehour. No hay horario de verano (DST) parahours. Solo hay un ajuste por horario de verano (DST) cuando la mediciónunites dedayo más y el cálculo cruza un cambio de horario en eltimezoneespecificado.