Dates with lubridate
lubridate is the tidyverse package that makes working with dates and times painless — it parses messy date strings, pulls out components like year or weekday, and does calendar-aware arithmetic without fiddly format codes.
Learn Dates with lubridate in our free R course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free R course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll parse dates with ymd() / mdy() / dmy() , extract parts with year() and wday() , add durations and periods, snap dates with floor_date() , and handle time zones.
What You'll Learn in This Lesson
1️⃣ Parsing & Accessing Components
The parser functions are named for the order the parts appear in your text: ymd() for year-month-day, mdy() for US month/day/year, dmy() for day-month-year. They're forgiving about separators and even accept month names.
With a real Date in hand, accessor functions read off each component. With label = TRUE , weekday and month come back as readable names.
2️⃣ Date Arithmetic: Durations & Periods
Subtracting two dates gives a difftime (a span). To add time, lubridate offers two flavours: durations (exact seconds) and periods (human, calendar-aware units). The difference shows up around leap days and month ends.
Reach for periods ( months() , years() ) when you mean "same day next month/year," and durations ( ddays() , dyears() ) when you need an exact physical elapsed time.
3️⃣ Rounding Dates & Time Zones
floor_date() snaps a date down to a unit boundary — the heart of turning fine-grained timestamps into weekly or monthly groups. Time zones, meanwhile, live on date- times (POSIXct): attach one when parsing, then shift the wall-clock with with_tz() .
A key distinction: with_tz() keeps the same instant in time and changes only how it's displayed, whereas force_tz() keeps the displayed clock and changes the underlying instant. Mixing these up is the most common time-zone bug.
Your turn. Fill in the # TODO blanks and run it.
Parse timestamps with the right combined parser, label the weekdays, measure the span, and group by week — the full lifecycle of date wrangling in one task.
📋 Quick Reference — lubridate
Practice quiz
Which parser reads "03/15/2024" as month/day/year?
- ymd()
- mdy()
- dmy()
- ydm()
Answer: mdy(). lubridate parsers are named for component order; mdy() matches month/day/year.
Which parser handles "2024-03-15" (year-month-day)?
- dmy()
- mdy()
- ymd()
- myd()
Answer: ymd(). ymd() parses year-month-day order into a real Date.
What does wday(d, label = TRUE) return?
- The day number only
- The labelled weekday name
- The year
- The week of the year
Answer: The labelled weekday name. With label = TRUE, wday() returns the weekday as a readable name like Fri.
What is the difference between a period and a duration?
- Periods are always shorter
- There is no difference
- Periods are exact seconds
- Periods are calendar-aware; durations are exact seconds
Answer: Periods are calendar-aware; durations are exact seconds. Periods (months(), years()) respect the calendar; durations (ddays()) are fixed seconds.
Which adds exactly 30 calendar days to a date?
- start + days(30)
- start + 30s
- start * 30
- start + month(30)
Answer: start + days(30). days(30) is a period adding 30 calendar days.
What does floor_date(d, "month") do?
- Adds a month
- Removes the day
- Snaps the date down to the first of its month
- Rounds to the nearest year
Answer: Snaps the date down to the first of its month. floor_date snaps a date down to the start of the chosen unit, e.g. the month.
Which parser handles a date that also includes a time?
- ymd_hms()
- ymd()
- hms()
- time()
Answer: ymd_hms(). Add the time order to the name: ymd_hms() parses date plus hour-minute-second.
What does with_tz() change?
- The underlying instant
- Only the displayed wall-clock time zone
- The date's year
- Nothing
Answer: Only the displayed wall-clock time zone. with_tz() keeps the same instant and only changes how it is displayed.
Why parse a date string instead of leaving it as text?
- It uses less memory
- Text sorts and subtracts correctly
- Parsing capitalizes months
- So it sorts and subtracts correctly as a Date
Answer: So it sorts and subtracts correctly as a Date. A plain string sorts alphabetically; a real Date sorts and subtracts correctly.
What does ceiling_date(d, "month") return?
- The start of the NEXT month
- The end of the year
- The same date
- The previous month
Answer: The start of the NEXT month. ceiling_date snaps up to the next unit boundary, here the first of next month.