Written and maintained by CASRAI Editorial Board
Last updated
lubridate is an R package for parsing, extracting, converting and doing arithmetic on dates and times. If you searched for “lubridate r” or “lubridate r package”: it is R-only (there is no Python port), it is MIT-licensed, and the current release on CRAN is 1.9.5 (published 2026-02-04). This page covers what it is for, how to install it, the core functions with exact outputs from its documentation, and the three-way distinction (durations, periods, intervals) that causes most date-arithmetic mistakes in research analysis.
What lubridate is used for in research
Research datasets are full of dates written in inconsistent ways: enrolment dates, sample collection times, instrument timestamps, follow-up windows. lubridate turns such text into proper date-time objects, pulls out components (year, month, weekday, hour), handles time zones, and computes elapsed time. Its documentation groups the functionality into parsing (ymd(), dmy(), mdy(), ymd_hms(), dmy_hms()), components (year(), month(), mday(), hour(), minute(), second(), wday()) and time zones (with_tz(), force_tz()).
For day-counting tasks specifically (adding, subtracting and counting days between two dates), see the task-focused guide R Days: Add, Subtract and Count Days Between Dates. This page is the package reference.
Install or access (official source only)
lubridate is distributed on CRAN, with its documentation site at lubridate.tidyverse.org. The package page lists R (>= 3.2) as a dependency and imports generics and timechange (>= 0.4.0). The official site gives these install routes:
install.packages("tidyverse")installs lubridate along with the other tidyverse packages.install.packages("lubridate")installs lubridate alone.devtools::install_github("tidyverse/lubridate")installs the development version from GitHub.
Then load it with library(lubridate). Call library(lubridate) explicitly in analysis scripts so the dependency is visible. Pinning the package version in your project record supports computational reproducibility.
Step-by-step: parse, extract and convert
1. Parse text into dates
Choose the function whose letters match the order of year (y), month (m) and day (d) in your data. Add h, m, s to the name for date-times.
library(lubridate)
ymd(20101215) # "2010-12-15"
mdy("4/1/17") # "2017-04-01"
bday <- dmy("14/10/1979")
time <- ymd_hms("2010-12-13 15:30:30")
2. Extract components
month(bday) # 10
wday(bday, label = TRUE) # Sun
3. Convert or fix time zones
with_tz() and force_tz() look similar but do opposite things. From the lubridate documentation:
with_tz(time, "America/Chicago") # "2010-12-13 09:30:30 CST" (same instant, different display)
force_tz(time, "America/Chicago") # "2010-12-13 15:30:30 CST" (clock time kept, instant changed)
Use force_tz() when a timestamp was recorded in the wrong zone (for example an instrument logging local time but read as UTC). Use with_tz() when the instant is right and you only want it displayed in another zone.
4. Round to a unit
According to the reference page, round_date() rounds to the nearest unit (halfway values round up), floor_date() rounds down to the unit boundary, and ceiling_date() rounds up. Valid base units include second, minute, hour, day, week, month, bimonth, quarter, season, halfyear and year. Flooring to "month" is a common way to bin observations for monthly counts.
Output and how to read it: durations, periods and intervals
lubridate has three ways to represent a span of time, and they give different answers around daylight-saving changes and month lengths.
| Class | Meaning | Example from the vignette |
|---|---|---|
| Duration | Exact number of seconds; the documentation says it “will always supply mathematically precise results” | dminutes(2) prints 120s (~2 minutes) |
| Period | Calendar units (months, days); length varies with the calendar | minutes(2) prints 2M 0S |
| Interval | A span tied to a specific start and end | interval(ymd(20110720, tz="Pacific/Auckland"), ymd(20110831, tz="Pacific/Auckland")) prints 2011-07-20 NZST--2011-08-31 NZST |
Intervals can be tested against dates: %within% returns a logical vector (for example whether meeting times fall inside a conference interval), and int_overlaps() returns TRUE when two intervals overlap. In a study context, an interval is the natural object for “was this visit inside the protocol window?”
The month-end trap
Adding a plain months() period to 31 January can produce an invalid date (NA), because not every month has a 31st. The vignette’s fix is the %m+% operator, which rolls back to the last valid day: jan31 %m+% months(0:11) yields 2013-02-28, 2013-04-30 and so on. Use it for follow-up schedules such as “monthly for 12 months from enrolment”.
Troubleshooting
- Result is
NAafter parsing. The text does not match the order implied by the function name, or the date is invalid (for example 31 April). Try the function with the matching y/m/d order for that column. - Result is
NAafter adding months. The month-end trap above; switch to%m+%. - Hours look shifted. Check whether you meant
with_tz()(display change) orforce_tz()(relabel the clock time), and whether the parse step was given the correcttzargument, as inymd_hms("2011-06-04 12:00:00", tz = "Pacific/Auckland"). - Elapsed time differs from a calendar expectation. You are probably mixing durations (exact seconds) and periods (calendar units); decide which one your protocol means.
Free alternatives
| Option | Language | Relationship to lubridate |
|---|---|---|
Base R (as.Date(), strptime(), as.POSIXct()) |
R | Ships with R, so needs no installation; parsing uses format strings rather than y/m/d function names. |
| clock | R | A separate R package for working with dates and times. |
pandas (pandas.to_datetime) |
Python | Python option, since lubridate is R-only. |
For a wider comparison of R with point-and-click statistics software, see SPSS vs R; for an applied R example see ANCOVA in R.
FAQ
Is lubridate part of the tidyverse?
Its documentation lives on the tidyverse site, and install.packages("tidyverse") installs it. You can also install it on its own with install.packages("lubridate").
Does lubridate exist for Python?
No. It is an R package. Python users typically use pandas or the standard library’s datetime module.
What is the difference between with_tz() and force_tz()?
with_tz() keeps the same instant and changes how it is displayed; force_tz() keeps the displayed clock time and changes the instant. See step 3 above for outputs.
Why do I get NA when I parse or add dates?
Either the text does not match the function’s y/m/d order, the date is not a real calendar date, or you added months to a month-end date. See Troubleshooting.
Which R and package versions does it need?
As listed on CRAN on 2026-11-08: version 1.9.5, R (>= 3.2), and the timechange package (>= 0.4.0) among its imports.
Sources (official documentation)
- lubridate documentation site, https://lubridate.tidyverse.org/ (read 2026-11-08)
- lubridate vignette, https://lubridate.tidyverse.org/articles/lubridate.html (read 2026-11-08)
- round_date reference, https://lubridate.tidyverse.org/reference/round_date.html (read 2026-11-08)
- CRAN package page, https://cran.r-project.org/package=lubridate (read 2026-11-08)







