8 Trabalhando com datas

Datas são um caso a parte no R. Existe uma própria classe para objetos desse tipo, chamada Date, com D maiúsculo. O R lida com datas no formato AAAA-MM-DD (Ano, Mês e Dia).

Abaixo, definimos um vetor com datas

x <- c("2014-07-15", "2018/03/20", "2019-12-31", "20170511")
as.Date(x)
## [1] "2014-07-15" NA           "2019-12-31" NA
class(as.Date(x))
## [1] "Date"

Perceba que o R nativamente não aceita qualquer separador entre o ano, o mês e o dia, apenas o traço. O pacote lubridate, que faz parte da família tidyverse, possui uma versão mais generalizável para isso:

library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
lubridate::as_date(x)
## [1] "2014-07-15" "2018-03-20" "2019-12-31" "2017-05-11"

A propósito, dominar o pacote lubridate, que possui funções muito simples de usar, é a única coisa necessária para saber lidar com datas no R. Por isso, este capítulo se dedica a mostrar as principais funções do pacote.

8.1 Gerar um vetor sequencial de datas

Essa tarefa é feita usando uma função nativa do R chamada seq.Date(), que possui quatro argumentos principais, sendo que três deles precisam ser especificados.

args(seq.Date)
## function (from, to, by, length.out = NULL, along.with = NULL, 
##     ...) 
## NULL
# gerar vetor de datas separadas por mes
seq.Date(from = as_date("2020-01-01"),
         to = as_date("2020-12-01"),
         by = "1 month")
##  [1] "2020-01-01" "2020-02-01" "2020-03-01" "2020-04-01" "2020-05-01" "2020-06-01" "2020-07-01" "2020-08-01" "2020-09-01"
## [10] "2020-10-01" "2020-11-01" "2020-12-01"
# gerar vetor de datas separadas por dia
seq.Date(from = as_date("2020-01-01"),
         to = as_date("2020-01-20"),
         by = "1 day")
##  [1] "2020-01-01" "2020-01-02" "2020-01-03" "2020-01-04" "2020-01-05" "2020-01-06" "2020-01-07" "2020-01-08" "2020-01-09"
## [10] "2020-01-10" "2020-01-11" "2020-01-12" "2020-01-13" "2020-01-14" "2020-01-15" "2020-01-16" "2020-01-17" "2020-01-18"
## [19] "2020-01-19" "2020-01-20"
# gerar vetor de datas separadas por 3 dias
seq.Date(from = as_date("2020-01-01"),
         to = as_date("2020-01-20"),
         by = "3 day")
## [1] "2020-01-01" "2020-01-04" "2020-01-07" "2020-01-10" "2020-01-13" "2020-01-16" "2020-01-19"
# gerar um vetor de 7 semanas separados por 1 semana
seq.Date(from = as_date("2020-01-01"),
         length.out = 7,
         by = "1 week")
## [1] "2020-01-01" "2020-01-08" "2020-01-15" "2020-01-22" "2020-01-29" "2020-02-05" "2020-02-12"

8.2 ‘Parsear’ datas e horários

Para fazer o R converter (ou parsear na linguagem de programação) um string em data, basta usar as funções correspondentes do lubridate.

Por exemplo, no vetor de exemplo x, definido acima, as datas já estavam definidas no formato correto: AAAA-MM-DD. Aqui no Brasil usamos outro formato: DD/MM/AAAA. O lubridate possui uma função pronta para essa situação:

# observer como usamos diferentes separadores
datas_brasil <- c("01/12/2019", "20/11/2018", "30011990", "17-03-2000")
# parseando o vetor acima para Data
dmy(datas_brasil)
## [1] "2019-12-01" "2018-11-20" "1990-01-30" "2000-03-17"

Caso o vetor também contenha dados de horário, basta incluir o sufixo referente a hora, minuto e segundo:

dmy_hms("30-09-2019 14:51:39")
## [1] "2019-09-30 14:51:39 UTC"
# sem o segundo
dmy_hm("30-09-2019 14:15")
## [1] "2019-09-30 14:15:00 UTC"
# apenas a hora
dmy_h("30-09-2019 15")
## [1] "2019-09-30 15:00:00 UTC"

8.3 Extrair componentes de uma data

É possível extrair qualquer tipo de componente de uma data ou de um vetor de datas com o lubridate. Veja alguns exemplos:

datas_brasil <- dmy_hms(c("01/12/2019 13:51:15", "20/11/2018 00:00:00", "30011990 080000", "17-03-2000 203000"))
datas_brasil
## [1] "2019-12-01 13:51:15 UTC" "2018-11-20 00:00:00 UTC" "1990-01-30 08:00:00 UTC" "2000-03-17 20:30:00 UTC"
# extrair componentes da data:
# ano
year(datas_brasil)
## [1] 2019 2018 1990 2000
# mes
month(datas_brasil)
## [1] 12 11  1  3
# dia
day(datas_brasil)
## [1]  1 20 30 17
# semana do ano
week(datas_brasil)
## [1] 48 47  5 11
# dia da semana
wday(datas_brasil, label = TRUE)
## [1] dom ter ter sex
## Levels: dom < seg < ter < qua < qui < sex < sáb
# trimestre
quarter(datas_brasil)
## [1] 4 4 1 1
# hora
hour(datas_brasil)
## [1] 13  0  8 20

8.4 Operações matemáticas com datas

Geralmente se está interessado em fazer três tipos de operações matemáticas com datas:

  • Adicionar uma quantidade N de dias/meses/anos/etc em uma data:
# adicionar 1 semana nas datas
datas_brasil + ddays(7)
## [1] "2019-12-08 13:51:15 UTC" "2018-11-27 00:00:00 UTC" "1990-02-06 08:00:00 UTC" "2000-03-24 20:30:00 UTC"
# adicionar 3 meses
datas_brasil + ddays(90)
## [1] "2020-02-29 13:51:15 UTC" "2019-02-18 00:00:00 UTC" "1990-04-30 08:00:00 UTC" "2000-06-15 20:30:00 UTC"
# adicionar 1 ano
datas_brasil + dyears(1)
## [1] "2020-11-30 19:51:15 UTC" "2019-11-20 06:00:00 UTC" "1991-01-30 14:00:00 UTC" "2001-03-18 02:30:00 UTC"
  • Calcular a diferença de tempo entre duas datas:

No R, subtrair datas segue a mesma sintaxe de subtrair números:

data1 <- dmy_hms("01/09/1993 20:00:00")
data2 <- dmy_hms("24-06-2018 17:00:00")

dif <- data2 - data1
dif
## Time difference of 9061.875 days

Por padrão, o R retorna a diferença em dias, mas em um objeto de classe difftime.

class(dif)
## [1] "difftime"

Recomenda-se então converter o output para a classe numeric:

as.numeric(dif)
## [1] 9061.875

Caso se deseje calcular essa diferença em outras unidades de tempo, como meses ou semanas, basta fazer a divisão correspondente:

# conveter para semanas
as.numeric(dif) / 7
## [1] 1294.554
# converter para meses
as.numeric(dif) / 30
## [1] 302.0625
# converter para anos
as.numeric(dif) / 365
## [1] 24.82705
  • Arredondar datas:

Para arredondar uma data, por exemplo, retornar o primeiro ou último dia da semana/mês/trimestre/etc de uma data de referência, usa-se as funções ceiling_date() (arredondar para cima) e floor_date() (para baixo):

# retornar a primeira data da semana:
floor_date(datas_brasil, "week")
## [1] "2019-12-01 UTC" "2018-11-18 UTC" "1990-01-28 UTC" "2000-03-12 UTC"
# retornar a ultima data do mês
# por padrao, ceiling_date retorna a primeira data do próximo mês,
# por isso é necessario subtrair o resultado por 1
ceiling_date(datas_brasil, "month") - 1
## [1] "2019-12-31 23:59:59 UTC" "2018-11-30 23:59:59 UTC" "1990-01-31 23:59:59 UTC" "2000-03-31 23:59:59 UTC"
# arredondar usando a hora como referencia
floor_date(datas_brasil, "hour")
## [1] "2019-12-01 13:00:00 UTC" "2018-11-20 00:00:00 UTC" "1990-01-30 08:00:00 UTC" "2000-03-17 20:00:00 UTC"