$dateDiff (agregação)
Nesta página
Definição
$dateDiff
Novidades na versão 5.0.
Retorna a diferença entre duas datas.
A expressão
$dateDiff
tem esta sintaxe:{ $dateDiff: { startDate: <Expression>, endDate: <Expression>, unit: <Expression>, timezone: <tzExpression>, startOfWeek: <String> } } Subtrai
startDate
deendDate
. Retorna um número inteiro nounit
especificado.CampoObrigatório/OpcionalDescriçãostartDate
Obrigatório
O início do período. O
startDate
pode ser qualquer expressão que resolva para uma Data, um carimbo de Data/hora ou um ObjectID.endDate
Obrigatório
unit
Obrigatório
A medição de tempo
unit
entrestartDate
eendDate
. É uma expressão que se resolve para uma string:year
quarter
week
month
day
hour
minute
second
millisecond
timezone
Opcional
O 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" startOfWeek
Opcional
Usado quando a unidade é igual a
week
. O padrão éSunday
. O parâmetrostartOfWeek
é uma expressão que resolve uma string que não diferencia maiúsculas de minúsculas:monday
(oumon
)tuesday
(outue
)wednesday
(ouwed
)thursday
(outhu
)friday
(oufri
)saturday
(ousat
)sunday
(ousun
)
Comportamento
Sem unidades fracionárias
A expressão $dateDiff
retorna a diferença de número inteiro entre startDate
e endDate
medido no units
especificado. As durações são medidas contando o número de vezes que um limite unitário é passado. Por exemplo, duas datas com 18 meses de diferença retornariam uma diferença de 1 year
em vez de 1,5 years
.
Início da semana
O início do week
é Sunday
, a menos que seja modificado pelo parâmetro startOfWeek
. Qualquer semana que comece entre startDate
e endDate
no dia especificado será contada. A contagem de semanas não é limitada pelo calendário month
ou pelo calendário year
.
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 }
Detalhes adicionais
O algoritmo calcula a diferença de data usando o calendário gregoriano.
Os anos bissextos e o horário de verão são contabilizados, mas não os segundos bissextos.
A diferença retornada pode ser negativa.
Exemplos
Tempo decorrido
Crie uma coleção de pedidos de clientes:
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") } ] )
O seguinte exemplo:
Retorna o número médio de dias para uma entrega.
Utiliza
dateDiff
para calcular a diferença entre a data depurchased
e a data dedelivered
.
db.orders.aggregate( [ { $group: { _id: null, averageTime: { $avg: { $dateDiff: { startDate: "$purchased", endDate: "$delivered", unit: "day" } } } } }, { $project: { _id: 0, numDays: { $trunc: [ "$averageTime", 1 ] } } } ] )
O acumulador de $avg
na etapa $group
utiliza $dateDiff
em cada documento para obter o tempo entre as datas de purchased
e delivered
. O valor resultante é retornado como averageTime
.
A parte decimal do averageTime
é truncada($trunc
) no estágio $project
para produzir uma saída como esta:
{ "numDays" : 4.6 }
Precisão do resultado
Crie esta coleção com datas de início e fim para uma assinatura.
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") } ] )
A expressão $dateDiff
retorna uma diferença de tempo expressa no número inteiro units
. Não há partes fracionárias de uma unidade. Por exemplo, ao contar em years
não há meios anos.
Neste exemplo, observe como alterar o unit
altera a precisão retornada:
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 } } ] )
Os resultados são resumidos nesta tabela:
Iniciar | End | Anos | Meses | Dias |
---|---|---|---|---|
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 |
A contagem só aumenta quando um novo unit
começa, portanto, 18 meses são relatados como 1 ano na segunda linha e 60 dias são relatados como um mês na terceira linha.
Semanas por mês
Crie uma coleção de meses:
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") }, ] )
Você pode alterar o início de cada semana e contar o número resultante de semanas em cada mês com o seguinte código:
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 } } ] )
Os resultados são resumidos nesta tabela:
Mês | Domingo | Segunda-feira | Sexta-feira |
---|---|---|---|
Janeiro | 5 | 4 | 4 |
Fevereiro | 4 | 3 | 4 |
Março | 4 | 4 | 4 |
Dos resultados:
Quando
startOfWeek
for domingo, dia 5week
de janeiro de 2021 começa no dia 31.Como o 31º é um domingo e está entre
startDate
eendDate
, umweek
é adicionado à contagem.A contagem de
week
é incrementada mesmo quando uma semana de calendário termina apósendDate
ou no próximo período de calendário.