Capítulo25 Fechas, horas y minutas
## [1] "2026-08-01"
El tema proviene de los siguientes sitios.
English: https://r4ds.had.co.nz/dates-and-times.html
Español: https://es.r4ds.hadley.nz/16-datetimes.html
25.2 Creando fechas/horas
En R y en los sistemas tipo Unix el tiempo se cuenta como el número de segundos (o días) transcurridos desde la medianoche del 1 de enero de 1970, conocida como la época Unix. Por eso as.numeric() de una fecha devuelve los días desde ese punto.
- date,
- time,
- date-time,
https://github.com/edgararuiz/guias-rapidas/blob/master/fechas.pdf
library(tidyverse)
library(lubridate) # paquete para convertir fechas
tidyverse_packages() # lista completa de los paquetes activado con **tidyverse**## [1] "broom" "conflicted" "cli" "dbplyr"
## [5] "dplyr" "dtplyr" "forcats" "ggplot2"
## [9] "googledrive" "googlesheets4" "haven" "hms"
## [13] "httr" "jsonlite" "lubridate" "magrittr"
## [17] "modelr" "pillar" "purrr" "ragg"
## [21] "readr" "readxl" "reprex" "rlang"
## [25] "rstudioapi" "rvest" "stringr" "tibble"
## [29] "tidyr" "xml2" "tidyverse"
25.3 El paquete lubridate
ymd(), mdy(), dmy() (lubridate) — convertir texto a fechas.
- Qué hacen: interpretan una cadena según el orden de sus partes:
ymd("2024-03-01"),mdy("3/1/2024"),dmy("1/3/2024"). - Con hora: añade
_hms,_hmo_h(p. ej.dmy_hms()). - Extraer partes:
year(),month(),day(),wday()(día de la semana).
La función today() regresa la fecha de hoy, similar a Sys.date()
## [1] "2026-08-01"
Use la función de tribble(), del paquete tibble, para crear una tabla manualmente
fechas <- tribble(
~ codigo, ~ fecha,
"001", "01/01/2019 00:00:00",
"002", "31/03/2019 01:05:00",
"003", "14/06/2019 20:00:00",
"004", "01/12/1859 11:32:13",
"005", "01/01/0501 05:04:33"
)
fechas## # A tibble: 5 × 2
## codigo fecha
## <chr> <chr>
## 1 001 01/01/2019 00:00:00
## 2 002 31/03/2019 01:05:00
## 3 003 14/06/2019 20:00:00
## 4 004 01/12/1859 11:32:13
## 5 005 01/01/0501 05:04:33
Hay varias opciones para convertir texto a fechas, el más usado es mdy_hms(), pero en este caso el formato utilizado no funciona bien.
Un error muy común es usar mdy() cuando las fechas están en formato día/mes/año. Como no existe un mes 31, obtendrás NA o fechas equivocadas; elige la función (dmy(), mdy(), ymd()) según el orden real de la fecha.
25.3.1 Un error tipico
## # A tibble: 5 × 2
## codigo fecha
## <chr> <dttm>
## 1 001 2019-01-01 00:00:00
## 2 002 NA
## 3 003 NA
## 4 004 1859-01-12 11:32:13
## 5 005 0501-01-01 05:04:33
Ya que el día es el primero, y no el mes, usamos dmy_hms()
## # A tibble: 5 × 2
## codigo fecha
## <chr> <dttm>
## 1 001 2019-01-01 00:00:00
## 2 002 2019-03-31 01:05:00
## 3 003 2019-06-14 20:00:00
## 4 004 1859-12-01 11:32:13
## 5 005 0501-01-01 05:04:33
lubridate tiene varias funciones para extraer partes de la fecha, por ejemplo: año, mes, día, hora, minuto, y cuatrimestre.
nueva_fechas %>%
mutate(a = year(fecha),
m = month(fecha),
d = day(fecha),
h = hour(fecha),
mn = minute(fecha),
q = quarter(fecha)
)## # A tibble: 5 × 8
## codigo fecha a m d h mn q
## <chr> <dttm> <int> <int> <int> <int> <int> <int>
## 1 001 2019-01-01 00:00:00 2019 1 1 0 0 1
## 2 002 2019-03-31 01:05:00 2019 3 31 1 5 1
## 3 003 2019-06-14 20:00:00 2019 6 14 20 0 2
## 4 004 1859-12-01 11:32:13 1859 12 1 11 32 4
## 5 005 0501-01-01 05:04:33 501 1 1 5 4 1
Las funciones round_date(), ceiling_date() y floor_date() permiten redondear la fecha al número más cercano de la unidad especificada
nueva_fechas %>%
mutate(
redondear = round_date(fecha, unit = " month"), # round_date es redondea al mes más cercano
techo = ceiling_date(fecha, unit = "day"), # ceiling_date redondea al día más cercano
suelo = floor_date(fecha, unit = "month"), # floor_date redondea al mes más cercano
suelo_hour= floor_date(fecha, unit = "hour") # redondea a la hora más cercana
)## # A tibble: 5 × 6
## codigo fecha redondear techo
## <chr> <dttm> <dttm> <dttm>
## 1 001 2019-01-01 00:00:00 2019-01-01 00:00:00 2019-01-01 00:00:00
## 2 002 2019-03-31 01:05:00 2019-04-01 00:00:00 2019-04-01 00:00:00
## 3 003 2019-06-14 20:00:00 2019-06-01 00:00:00 2019-06-15 00:00:00
## 4 004 1859-12-01 11:32:13 1859-12-01 00:00:00 1859-12-02 00:00:00
## 5 005 0501-01-01 05:04:33 0501-01-01 00:00:00 0501-01-02 00:00:00
## # ℹ 2 more variables: suelo <dttm>, suelo_hour <dttm>
25.4 Intervalos y duraciones
La función interval() crea un objeto R de intervalo de tiempo. En este caso, el intervalo entre la fecha en la tabla, y el día de hoy. Nota que esto puede ser muy útil si quiere calcular la cantidad de tiempo entre dos fechas.
## # A tibble: 5 × 3
## codigo fecha intervalo
## <chr> <dttm> <Interval>
## 1 001 2019-01-01 00:00:00 2019-01-01 00:00:00 UTC--2026-08-01 UTC
## 2 002 2019-03-31 01:05:00 2019-03-31 01:05:00 UTC--2026-08-01 UTC
## 3 003 2019-06-14 20:00:00 2019-06-14 20:00:00 UTC--2026-08-01 UTC
## 4 004 1859-12-01 11:32:13 1859-12-01 11:32:13 UTC--2026-08-01 UTC
## 5 005 0501-01-01 05:04:33 0501-01-01 05:04:33 UTC--2026-08-01 UTC
int_length() regresa el número de segundos dentro del intervalo
nueva_fechas %>%
mutate(
intervalo = interval(fecha, today()), #
segundos = int_length(intervalo) # número de segundos en el intervalo
)## # A tibble: 5 × 4
## codigo fecha intervalo segundos
## <chr> <dttm> <Interval> <dbl>
## 1 001 2019-01-01 00:00:00 2019-01-01 00:00:00 UTC--2026-08-01 UTC 239241600
## 2 002 2019-03-31 01:05:00 2019-03-31 01:05:00 UTC--2026-08-01 UTC 231548100
## 3 003 2019-06-14 20:00:00 2019-06-14 20:00:00 UTC--2026-08-01 UTC 225000000
## 4 004 1859-12-01 11:32:13 1859-12-01 11:32:13 UTC--2026-08-01 UTC 5259472067
## 5 005 0501-01-01 05:04:33 0501-01-01 05:04:33 UTC--2026-08-01 UTC 48142666527
25.5 El operador %--% simplifica el cálculo del intervalo
Compara con el script anterior
## # A tibble: 5 × 3
## codigo fecha intervalo
## <chr> <dttm> <Interval>
## 1 001 2019-01-01 00:00:00 2019-01-01 00:00:00 UTC--2026-08-01 UTC
## 2 002 2019-03-31 01:05:00 2019-03-31 01:05:00 UTC--2026-08-01 UTC
## 3 003 2019-06-14 20:00:00 2019-06-14 20:00:00 UTC--2026-08-01 UTC
## 4 004 1859-12-01 11:32:13 1859-12-01 11:32:13 UTC--2026-08-01 UTC
## 5 005 0501-01-01 05:04:33 0501-01-01 05:04:33 UTC--2026-08-01 UTC
Para saber el número de días en el intervalo, divida el intervalo por la función que corresponde a días, days()
nueva_fechas %>%
mutate(dias = fecha %--% today() / days(),
anio= fecha %--% today() / years()) # número de días en el intervalo## # A tibble: 5 × 4
## codigo fecha dias anio
## <chr> <dttm> <dbl> <dbl>
## 1 001 2019-01-01 00:00:00 2769 7.58
## 2 002 2019-03-31 01:05:00 2680. 7.34
## 3 003 2019-06-14 20:00:00 2604. 7.13
## 4 004 1859-12-01 11:32:13 60874. 167.
## 5 005 0501-01-01 05:04:33 557207. 1526.
Intervalo entre una lista de fecha y otra fecha y hora específica
## # A tibble: 5 × 3
## codigo fecha dias
## <chr> <dttm> <dbl>
## 1 001 2019-01-01 00:00:00 365
## 2 002 2019-03-31 01:05:00 276.
## 3 003 2019-06-14 20:00:00 200.
## 4 004 1859-12-01 11:32:13 58470.
## 5 005 0501-01-01 05:04:33 554803.
25.6 Ejercicio
Usa esta función y calcula el número de día que ha transcurrido entre el día de su nacimiento y el día de hoy
## [1] 251337600
## [1] 2909
## [1] 95.58065
## [1] 7.964384
## [1] 251337600000
Los resultados se pueden visualizar usando ggplot2
nueva_fechas %>%
mutate(dias = fecha %--% today() / years()) %>%
ggplot() +
geom_col(aes(codigo, dias)) +
coord_flip()
25.7 Serie de funciones para calcular la duración de un intervalo de tiempo.
- dyears() # años
- dmonths() # meses
- dweeks() # semanas
- ddays() # días
- dhours() # horas
- dminutes() # minutos
- dseconds() # segundos
- dmilliseconds() # milisegundos
- dmicroseconds() # microsegundos
- dnanoseconds() # nanosegundos
- dpicoseconds() # picosegundos
25.8 as.duration
as.duration() crea un objecto en R que contiene la duración del intervalo de tiempo.
nueva_fechas %>%
mutate(desde_hoy = as.duration(fecha %--% today())) # duración desde la fecha hasta hoy## # A tibble: 5 × 3
## codigo fecha desde_hoy
## <chr> <dttm> <Duration>
## 1 001 2019-01-01 00:00:00 239241600s (~7.58 years)
## 2 002 2019-03-31 01:05:00 231548100s (~7.34 years)
## 3 003 2019-06-14 20:00:00 2.25e+08s (~7.13 years)
## 4 004 1859-12-01 11:32:13 5259472067s (~166.66 years)
## 5 005 0501-01-01 05:04:33 48142666527s (~1525.55 years)
El objeto de duración de tiempo se puede filtrar fácilmente basado en una variedad de tipo de tiempos. En este caso, semanas dweeks() crea un objeto de duración de la largura especificada
nueva_fechas %>%
mutate(desde_hoy = as.duration(fecha %--% today())) %>%
filter(desde_hoy > dyears(7))## # A tibble: 5 × 3
## codigo fecha desde_hoy
## <chr> <dttm> <Duration>
## 1 001 2019-01-01 00:00:00 239241600s (~7.58 years)
## 2 002 2019-03-31 01:05:00 231548100s (~7.34 years)
## 3 003 2019-06-14 20:00:00 2.25e+08s (~7.13 years)
## 4 004 1859-12-01 11:32:13 5259472067s (~166.66 years)
## 5 005 0501-01-01 05:04:33 48142666527s (~1525.55 years)
Otra opción es ddays().
nueva_fechas %>%
mutate(desde_hoy = as.duration(fecha %--% today())) %>%
filter(desde_hoy < ddays(2500)) # Nota que se puede filtrar por el número de días que han acumulado## # A tibble: 0 × 3
## # ℹ 3 variables: codigo <chr>, fecha <dttm>, desde_hoy <Duration>
25.9 Crear una fecha desde columnas individuales
- make_date()
- make_datetime()
Unir el año, mes, día, hora y minutos que estén en diferentes columnas en uno
- sumamente practico cuando se tiene una base de datos con las fechas en diferentes columnas
## # A tibble: 6 × 19
## anio mes dia horario_salida salida_programada atraso_salida
## <int> <int> <int> <int> <int> <dbl>
## 1 2013 1 1 517 515 2
## 2 2013 1 1 533 529 4
## 3 2013 1 1 542 540 2
## 4 2013 1 1 544 545 -1
## 5 2013 1 1 554 600 -6
## 6 2013 1 1 554 558 -4
## # ℹ 13 more variables: horario_llegada <int>, llegada_programada <int>,
## # atraso_llegada <dbl>, aerolinea <chr>, vuelo <int>, codigo_cola <chr>,
## # origen <chr>, destino <chr>, tiempo_vuelo <dbl>, distancia <dbl>,
## # hora <dbl>, minuto <dbl>, fecha_hora <dttm>
vuelos %>%
dplyr::select(anio, mes, dia, hora, minuto) %>%
mutate(salida_dia=make_date(anio, mes, dia),
salida_dia_minutos = make_datetime(anio, mes, dia, hora, minuto))## # A tibble: 336,776 × 7
## anio mes dia hora minuto salida_dia salida_dia_minutos
## <int> <int> <int> <dbl> <dbl> <date> <dttm>
## 1 2013 1 1 5 15 2013-01-01 2013-01-01 05:15:00
## 2 2013 1 1 5 29 2013-01-01 2013-01-01 05:29:00
## 3 2013 1 1 5 40 2013-01-01 2013-01-01 05:40:00
## 4 2013 1 1 5 45 2013-01-01 2013-01-01 05:45:00
## 5 2013 1 1 6 0 2013-01-01 2013-01-01 06:00:00
## 6 2013 1 1 5 58 2013-01-01 2013-01-01 05:58:00
## 7 2013 1 1 6 0 2013-01-01 2013-01-01 06:00:00
## 8 2013 1 1 6 0 2013-01-01 2013-01-01 06:00:00
## 9 2013 1 1 6 0 2013-01-01 2013-01-01 06:00:00
## 10 2013 1 1 6 0 2013-01-01 2013-01-01 06:00:00
## # ℹ 336,766 more rows
Unir el año, mes, día, hora que estén en diferentes columnas en uno
vuelos %>%
dplyr::select(anio, mes, dia, hora, minuto) %>%
mutate(salida2 = make_date(anio, mes, dia))## # A tibble: 336,776 × 6
## anio mes dia hora minuto salida2
## <int> <int> <int> <dbl> <dbl> <date>
## 1 2013 1 1 5 15 2013-01-01
## 2 2013 1 1 5 29 2013-01-01
## 3 2013 1 1 5 40 2013-01-01
## 4 2013 1 1 5 45 2013-01-01
## 5 2013 1 1 6 0 2013-01-01
## 6 2013 1 1 5 58 2013-01-01
## 7 2013 1 1 6 0 2013-01-01
## 8 2013 1 1 6 0 2013-01-01
## 9 2013 1 1 6 0 2013-01-01
## 10 2013 1 1 6 0 2013-01-01
## # ℹ 336,766 more rows
## Conversión de fechas que no son estándar
Datos_raros=tribble(~Ind, ~Persona, ~fecha_de_nacimiento,
1, "Abuela", "1/1/30",
2, "Abuelo","1/30/01",
3, "Tio", "1/30/09")
Datos_raros ## # A tibble: 3 × 3
## Ind Persona fecha_de_nacimiento
## <dbl> <chr> <chr>
## 1 1 Abuela 1/1/30
## 2 2 Abuelo 1/30/01
## 3 3 Tio 1/30/09
## # A tibble: 3 × 4
## Ind Persona fecha_de_nacimiento nueva_fecha
## <dbl> <chr> <chr> <date>
## 1 1 Abuela 1/1/30 2030-01-01
## 2 2 Abuelo 1/30/01 2001-01-30
## 3 3 Tio 1/30/09 2009-01-30
## [1] "1970-01-01"
df <- tibble(
Persona = c("Abuela", "Abuelo", "Tio"),
fecha_de_nacimiento = c("1/1/1930", "1/30/1901", "1/30/1909")
)
df <- df %>%
mutate(
nueva_fecha = mdy(fecha_de_nacimiento),
nueva_fecha = if_else(year(nueva_fecha) > year(today()),
nueva_fecha - years(100),
nueva_fecha)
)
df## # A tibble: 3 × 3
## Persona fecha_de_nacimiento nueva_fecha
## <chr> <chr> <date>
## 1 Abuela 1/1/1930 1930-01-01
## 2 Abuelo 1/30/1901 1901-01-30
## 3 Tio 1/30/1909 1909-01-30
#Datos_raros$fecha2=as.Date(as.Date(format(as.Date(Datos_raros$fecha_de_nacimiento, format="%m/%d/%Y"), "19%y%m%d"), "%Y%m%d"))
#Datos_raros*** HERE ***
25.10 %/%: integer division
vuelos |> dplyr::select(tiempo_vuelo) |>
mutate(t=tiempo_vuelo %/% 100) |> # Division
mutate(m= tiempo_vuelo %% 100) # modulus... Cambia el 100 para 1, 10, 1000... y mira cual es el resultado## # A tibble: 336,776 × 3
## tiempo_vuelo t m
## <dbl> <dbl> <dbl>
## 1 227 2 27
## 2 227 2 27
## 3 160 1 60
## 4 183 1 83
## 5 116 1 16
## 6 150 1 50
## 7 158 1 58
## 8 53 0 53
## 9 140 1 40
## 10 138 1 38
## # ℹ 336,766 more rows
25.11 The %% operator returns the modulus (remainder) of a division operation.
- For instance, 5 %% 2 would return 1, as the remainder of 5 divided by 2 is 1.
## [1] "anio" "mes" "dia"
## [4] "horario_salida" "salida_programada" "atraso_salida"
## [7] "horario_llegada" "llegada_programada" "atraso_llegada"
## [10] "aerolinea" "vuelo" "codigo_cola"
## [13] "origen" "destino" "tiempo_vuelo"
## [16] "distancia" "hora" "minuto"
## [19] "fecha_hora"
hacer_fechahora_100 <- function(anio, mes, dia, tiempo) {
make_datetime(anio, mes, dia, tiempo %/% 100, tiempo %% 100)
}
vuelos_dt <- vuelos %>%
filter(!is.na(horario_salida), !is.na(horario_llegada)) %>%
mutate(
horario_salida = hacer_fechahora_100(anio, mes, dia, horario_salida),
horario_llegada = hacer_fechahora_100(anio, mes, dia, horario_llegada),
salida_programada = hacer_fechahora_100(anio, mes, dia, salida_programada),
llegada_programada = hacer_fechahora_100(anio, mes, dia, llegada_programada)
) %>%
dplyr::select(origen, destino, starts_with("atraso"), starts_with("horario"), ends_with("programada"), tiempo_vuelo)
head(vuelos_dt)## # A tibble: 6 × 9
## origen destino atraso_salida atraso_llegada horario_salida
## <chr> <chr> <dbl> <dbl> <dttm>
## 1 EWR IAH 2 11 2013-01-01 05:17:00
## 2 LGA IAH 4 20 2013-01-01 05:33:00
## 3 JFK MIA 2 33 2013-01-01 05:42:00
## 4 JFK BQN -1 -18 2013-01-01 05:44:00
## 5 LGA ATL -6 -25 2013-01-01 05:54:00
## 6 EWR ORD -4 12 2013-01-01 05:54:00
## # ℹ 4 more variables: horario_llegada <dttm>, salida_programada <dttm>,
## # llegada_programada <dttm>, tiempo_vuelo <dbl>
25.11.0.1 Cuantos segundos hay en un dia?
vuelos_dt %>%
ggplot(aes(horario_salida)) +
geom_freqpoly(binwidth = 86400) # 86400 segundos = 1 día
vuelos_dt %>%
filter(horario_salida < ymd(20130102)) %>%
ggplot(aes(horario_salida)) +
geom_freqpoly(binwidth = 600) # 600 segundos = 10 minutos
Nota variables que no funciona
## [1] "2010-10-10" NA
## [1] "Jan 1, 2010"
## [1] "2010-01-01"
## [1] "2015-Mar-07"
## [1] "2015-03-07"
## [1] "06-Jun-2017"
## [1] "2017-06-06"
## [1] "Aug 19 (2015)" "Jul 1 (2015)"
## [1] "2015-08-19" "2015-07-01"
## [1] "12/30/14"
## [1] "2014-12-30"
## [1] "ene 1, 2010"
## [1] NA
## [1] "Agosto 19 (2015)" "Julio 1 (2015)"
## [1] NA NA
## [1] "2010-01-01"
## [1] "2015-03-07"
## [1] "2017-06-06"
## [1] "2015-08-19" "2015-07-01"
## [1] "2014-12-30"
## [1] NA
## [1] NA NA
- Ejercicios:
Hacer los ejercicios en la sección 16.2.4 del libro en español
25.12 Extrayendo parte de las fecha-hora
year()
month()
mday()
yday()
wday()
ceiling_date()
floor_date()
round_date()
- Ejercicios:
Hacer estos ejercicios en la sección 16.3.4 del libro en español. Entregar por MSTeams.
¿Cómo cambia la demora promedio durante el curso de un día? ¿Deberías usar horario_salida o salida_programada? ¿Por qué?
¿En qué día de la semana deberías salir si quieres minimizar las posibilidades de una demora?
Confirma nuestra hipótesis de que las salidas programadas en los minutos 20-30 y 50-60 están causadas por los vuelos programados que salen más temprano. Pista: crea una variable binaria que te diga si un vuelo tuvo o no demora.
25.14 duraciones
# ¿Qué edad tiene Charles Darwin? fecha de naciemiento February 12, 1809
edad_h <- today() - ymd("1809-02-12")
edad_h <- today() - ymd(18090212)
edad_h## Time difference of 79428 days
## [1] "6862579200s (~217.46 years)"
Otras funciones de duración
## [1] "15s"
## [1] "600s (~10 minutes)"
## [1] "43200s (~12 hours)" "86400s (~1 days)"
## [1] "0s" "86400s (~1 days)" "172800s (~2 days)"
## [4] "259200s (~3 days)" "345600s (~4 days)" "432000s (~5 days)"
## [1] "1814400s (~3 weeks)"
## [1] "31557600s (~1 years)"
25.15 Puede agregar periodos de tiempo
## [1] "63115200s (~2 years)"
## [1] "38869200s (~1.23 years)"
## [1] "2026-07-31"
## [1] "2025-07-31 18:00:00 UTC"
25.16 períodos
## [1] "2016-03-12 13:00:00 EST"
## [1] "2016-03-13 14:00:00 EDT"
## [1] "15S"
## [1] "10M 0S"
## [1] "12H 0M 0S" "24H 0M 0S"
## [1] "7d 0H 0M 0S"
## [1] "1m 0d 0H 0M 0S" "2m 0d 0H 0M 0S" "3m 0d 0H 0M 0S" "4m 0d 0H 0M 0S"
## [5] "5m 0d 0H 0M 0S" "6m 0d 0H 0M 0S"
#> [1] "1m 0d 0H 0M 0S" "2m 0d 0H 0M 0S" "3m 0d 0H 0M 0S" "4m 0d 0H 0M 0S"
#> [5] "5m 0d 0H 0M 0S" "6m 0d 0H 0M 0S"
weeks(3)## [1] "21d 0H 0M 0S"
## [1] "1y 0m 0d 0H 0M 0S"
## [1] "60m 10d 0H 0M 0S"
## [1] "50d 25H 2M 0S"
## [1] "2016-12-31 06:00:00 UTC"
## [1] "2017-01-01"
## [1] "2016-03-13 14:00:00 EDT"
## [1] "2016-03-13 13:00:00 EDT"
## [1] "60m 10d 0H 0M 0S"
## [1] "50d 25H 2M 0S"
- intervalos
25.20 Time zones
- Sys.timezone()
- head(OlsonNames())
- tz= “”
- Ejercicios:
Seleccionar 3 archivos de los vuelos que salen o llegan a PR, (el código del aeropuerto es “SJU”) de la base de datos de https://www.transtats.bts.gov/DL_SelectFields.asp?Table_ID=236 Pueden ser el mismo mes en 3 diferentes años o 3 diferentes meses en el mismo año.
Repite la mayoría de los análisis enseñado arriba (como práctica).
Evaluar el tiempo de retraso de los vuelos que salen de SJU en cada periodo seleccionado, y haz una gráfica para visualizar el patrón
Cuál es el día preferible para no tener retraso
Cuál es la mejor hora de salida para no tener retraso
Compara por lo menos 3 diferentes líneas saliendo de SJU y el periodo de retraso.