$dateAdd (agregação)
Nesta página
Definição
$dateAdd
Novidades na versão 5.0.
Incrementa um objeto
Date()
em um número especificado de unidades de tempo.A expressão
$dateAdd
tem a seguinte sintaxe:{ $dateAdd: { startDate: <Expression>, unit: <Expression>, amount: <Expression>, timezone: <tzExpression> } } Retorna um
Date()
. OstartDate
pode ser qualquer expressão que resolva o tipo Date, Timestamp ou ObjectId. Não importa qual tipo de dados é usado como entrada, o valor retornado será um objetoDate()
.CampoObrigatório/OpcionalDescriçãostartDate
Obrigatóriounit
ObrigatórioO
unit
usado para medir oamount
de tempo adicionado aostartDate
. Ounit
é uma expressão que se resolve em uma das seguintes strings:year
quarter
week
month
day
hour
minute
second
millisecond
amount
ObrigatórioO número deunits
adicionado aostartDate
. Oamount
é uma expressão que resolve para um inteiro ou longo. Oamount
também pode ser resolvido como um decimal integral ou double se esse valor puder ser convertido em um valor longo sem perda de precisão.timezone
OpcionalO fuso horário para realizar a operação.
<tzExpression>
deve ser uma expressão válida que resolva para uma string formatada como um identificador de fuso horário Olson ou um UTC Offset. Se nenhumtimezone
for fornecido, o resultado será exibido emUTC
.FormatarExemplosIdentificador de fuso horário Olson"America/New_York" "Europe/London" "GMT" UTC Offset+/-[hh]:[mm], e.g. "+04:45" +/-[hh][mm], e.g. "-0530" +/-[hh], e.g. "+03" Para mais informações sobre expressões e tipos, consulte Operadores de Expressão e Tipos de JSON.
Comportamento
Medição de tempo
O MongoDB segue o uso predominante do banco de dados e trabalha com o tempo em UTC. A expressão dateAdd
sempre pega um startDate
em UTC e retorna um resultado em UTC. Se o timezone
for especificado, o cálculo será feito utilizando o timezone
especificado. O fuso horário é especialmente importante quando um cálculo envolve Horário de Verão (DST).
Se unit
for month
ou maior, a operação será ajustada para contabilizar o último dia do mês. Adicionar um month
no último dia de outubro, por exemplo, demonstra o ajuste de "último dia do mês".
{ $dateAdd: { startDate: ISODate("2020-10-31T12:10:05Z"), unit: "month", amount: 1 } }
Observe que a data retornada, ISODate("2020-11-30T12:10:05Z")
, é 30 e não 31, pois novembro tem menos dias do que outubro.
Fuso horário
Ao usar um Identificador de Fuso Horário Olson no campo <timezone>
, o MongoDB aplica o deslocamento de horáriode verão , se aplicável, para o fuso horário especificado.
Por exemplo, considere uma collection sales
com o seguinte documento:
{ "_id" : 1, "item" : "abc", "price" : 20, "quantity" : 5, "date" : ISODate("2017-05-20T10:24:51.303Z") }
A seguinte agregação ilustra como o MongoDB lida com o deslocamento DST para o Identificador de fuso horário Olson. O exemplo utiliza os operadores $hour
e $minute
para retornar as partes correspondentes do campo 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" } } } }])
A operação retorna o seguinte resultado:
{ "_id": 1, "nycHour" : 5, "nycMinute" : 24, "gmtHour" : 10, "gmtMinute" : 24, "nycOlsonHour" : 6, "nycOlsonMinute" : 24 }
Exemplos
Adicionar uma data futura
Considere uma coleção de pedidos de clientes com estes documentos:
db.shipping.insertMany( [ { custId: 456, purchaseDate: ISODate("2020-12-31") }, { custId: 457, purchaseDate: ISODate("2021-02-28") }, { custId: 458, purchaseDate: ISODate("2021-02-26") } ] )
O tempo normal de envio é de 3 dias. Você pode usar $dateAdd
em um aggregation pipeline para definir expectedDeliveryDate
3 dias no futuro.
db.shipping.aggregate( [ { $project: { expectedDeliveryDate: { $dateAdd: { startDate: "$purchaseDate", unit: "day", amount: 3 } } } }, { $merge: "shipping" } ] )
Após adicionar 3 dias ao purchaseDate
com $dateAdd
no estágio $project
, o estágio $merge
atualiza os documentos originais com o expectedDeliveryDate
.
Os documentos resultantes têm a seguinte aparência:
{ "_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") }
Filtrar em um intervalo de datas
Atualize a coleção shipping
do último exemplo com este código para adicionar datas de entrega aos documentos:
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" ) } } )
Você deseja encontrar remessas atrasadas. Use $dateAdd
em um estágio $match
para criar um filtro que corresponda a documentos em uma faixa de datas definido por um ponto de partida ($purchaseDate
) e um período dado por $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" } } } } ] )
O estágio $match
utiliza $gt
e $dateAdd
em uma expressão ($expr
) para comparar o deliveryDate
real com uma data esperada. Os documentos com datas de entrega superiores a 5 dias após o purchaseDate
são passados para a etapa $project
.
O estágio $project
utiliza a expressão $dateToString
para converter as datas em um formato mais legível. Sem a conversão, o MongoDB retorna a data no formato ISODate e assume um fuso horário UTC.
Neste exemplo, apenas um registro é retornado:
{ "custId" : 456, "purchased" : "2020-12-31", "delivery" : "2021-01-10" }
Ajustar para o horário de verão
Todas as datas são armazenadas internamente no horário UTC. Quando um timezone
é especificado, o $dateAdd
utiliza a hora local para executar os cálculos. Os resultados são exibidos em UTC.
Você tem clientes em vários fusos horários e deseja ver o efeito que o horário de verão pode ter em seus períodos de faturamento se você faturar por day
ou por hour
.
Criar esta coleção de tempos de conexão:
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") } ] )
Primeiro, adicione 1 dia e, em seguida, adicione 24 horas às datas login
em 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: { $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()
A expressão $dateToString
reformata a saída para legibilidade. Os resultados são resumidos aqui:
Campo | New York | Cidade do México |
---|---|---|
Iniciar | 2021-03-13 15:00 | 2021-03-13 10:00 |
Início, TZ Info | 2021-03-13 10:00 | 2021-03-13 04:00 |
1 dia | 2021-03-14 14:00 | 2021-03-14 10:00 |
1 dia, informações TZ | 2021-03-14 10:00 | 2021-03-14 04:00 |
24 horas | 2021-03-14 15:00 | 2021-03-14 10:00 |
24 horas, informações sobre TZ | 2021-03-14 11:00 | 2021-03-14 04:00 |
O gráfico destaca vários pontos:
As datas não formatadas retornam em UTC. O
$login
para Nova York é UTC -5, no entanto, as linhasstart
,days
ehours
exibem o tempo em UTC.de março é o início do DST em Nova York, mas não no México. O tempo calculado é ajustado quando um local muda para DST e cruza de um
day
para o outro.O horário de verão modifica o comprimento do
day
, não dohour
. Não há alteração de DST parahours
. Só há um ajuste para o horário de verão quando a medidaunit
éday
ou maior e o cálculo ultrapassa uma mudança de relógio notimezone
especificado.