Dates and times with lubridate

R
beginner
Published

May 17, 2024

No feedback found for this session

Slides

Slides

Session content

Word of warning

  • dates and times are hard everywhere
  • R is no exception
  • this session is a beginner’s guide to lubridate
    • not the only way of dealing with dates
    • not always the best
    • on balance the most consistent, and least quirky tools for dates

This session

  • beginner-friendly
  • focus on core parsing, get/set, and rounding functions
  • lots on dates, a bit of date-times, no times

Resources

library(lubridate)

R dates

  • days since 1970-01-01
as_date(0)

[1] “1970-01-01”

R dates

as_date(19860)

[1] “2024-05-17”

as_date(1:5)

[1] “1970-01-02” “1970-01-03” “1970-01-04” “1970-01-05” “1970-01-06”

class(as_date(0))

[1] “Date”

R date-times

  • seconds since 1970-01-01 00:00:00 UTC
as_datetime(0)

[1] “1970-01-01 UTC”

as_datetime(1715935369)

[1] “2024-05-17 08:42:49 UTC”

as_datetime(0:5)

[1] “1970-01-01 00:00:00 UTC” “1970-01-01 00:00:01 UTC” [3] “1970-01-01 00:00:02 UTC” “1970-01-01 00:00:03 UTC” [5] “1970-01-01 00:00:04 UTC” “1970-01-01 00:00:05 UTC”

class(as_datetime(0))

[1] “POSIXct” “POSIXt”

Famously…

as_datetime(2 ^ 31-1) # 32 bit signed int

[1] “2038-01-19 03:14:07 UTC”

Parsing dates is important

  • most functions that accept dates (like ggplot) will mis-behave if you feed them date-shaped-words
    • e.g. alphabetically-ordered dates
  • we also want to be able to calculate with dates

Couple of fun intro functions

today()

[1] “2024-09-26”

date_decimal(2024.37534)

[1] “2024-05-17 08:59:11 UTC”

now()

[1] “2024-09-26 13:59:12 UTC”

now("Japan")

[1] “2024-09-26 22:59:12 JST”

random_zone <- sample(OlsonNames(), 1)
cat(paste("The date-time in", random_zone, "is", now(sample(OlsonNames(), 1))))

The date-time in America/Ensenada is 2024-09-26 18:59:12.459654

Parsing

  • as_date() is fine assuming you have your date as a number of days
  • but usually, we’ll need to parse our dates
as_date(45429) # excel-format 1900 date

[1] “2094-05-19”

as_date(45429 - 25569) # dirty but effective

[1] “2024-05-17”

as_date(45429, origin = "1899-12-30") # better

[1] “2024-05-17”

Parsing

  • more often, we’ll be taking human-readable dates and parsing them
  • that’s a pain, because there are loads of inconsistent ways of representing dates
  • worse, lots of dates are ambiguous (5/6/24 and 6/5/24 might refer to the same day)
date_input <- c("17/5/24", "2024-05-17", "Friday 17th May 2024", "17*May*24", "5/17/2024" )

as_date(date_input) # as_date expects ISO-8601ish dates

[1] “2017-05-24” “2024-05-17” NA “2017-05-24” NA

# one correct, two silently incorrent, two NAs

parse_date_time

parse_date_time(date_input, orders = "ymd")

[1] “2017-05-24 UTC” “2024-05-17 UTC” NA “2017-05-24 UTC” [5] NA

parse_date_time(date_input, orders = c("dmy", "ymd", "dmy", "dmy", "mdy"))

[1] “2024-05-17 UTC” “2024-05-17 UTC” “2024-05-17 UTC” “2024-05-17 UTC” [5] “2024-05-17 UTC”

dmy and co

  • you can also use the orders (like dmy) as standalone parsing functions:
dmy(date_input[c(1,3,4)])

[1] “2024-05-17” “2024-05-17” “2024-05-17”

ymd_hms("2024-05/17 9-05-01")

[1] “2024-05-17 09:05:01 UTC”

So you can make dates/date-times. So what?

date(now())

[1] “2024-09-26”

year(today())

[1] 2024

leap_year(today())

[1] TRUE

quarter(today())

[1] 3

semester(today())

[1] 2

semester(today(), with_year = T)

[1] 2024.2

Months and weeks

month(today())

[1] 9

month(today(), label = T)

[1] Sep 12 Levels: Jan < Feb < Mar < Apr < May < Jun < Jul < Aug < Sep < … < Dec

week(today())

[1] 39

epiweek(today()) # special ways of counting weeks. See  https://en.wikipedia.org/wiki/ISO_week_date and https://www.cmmcp.org/mosquito-surveillance-data/pages/epi-week-calendars-2008-2024

[1] 39

Days

day(today())

[1] 26

wday(today())

[1] 5

qday(today())

[1] 88

Hour and minute

hour(now())

[1] 13

minute(now())

[1] 59

am(now())

[1] FALSE

dst(now()) 

[1] FALSE

Set

update(now(), hour = 11, minute = 0, second = 0) # nominal finish time today

[1] “2024-09-26 11:00:00 UTC”

  • or, more generally:
test_date <- dmy("05/06/23")
day(test_date)

[1] 5

day(test_date) <- 11
test_date

[1] “2023-06-11”

Round

floor_date(today(), unit = "week")

[1] “2024-09-22”

round_date(today(), unit = "week")

[1] “2024-09-29”

ceiling_date(today(), unit = "month")

[1] “2024-10-01”

rollback(today()) # last day of previous month

[1] “2024-08-31”