Skip to Content
Course content

48: Date and Time Handling with lubridate

Click on the "Edit" button in the top corner of the screen to edit your slide content.

If you've spent any time with base R, you know that dealing with dates and times can feel like a fight you're destined to lose. The formats are finicky, and the `POSIXct` and `POSIXlt` classes are, frankly, a headache. That's why we use lubridate. It turns date-time manipulation into something that actually feels intuitive.

To show you how this works, let's imagine we're analyzing a small set of logs from a temperature sensor. We have a few timestamps and the recorded temperature, but they're currently just strings in a data frame. We need to find out how much time elapsed between readings and what time of day the sensor is most active.

Cleaning up messy sensor timestamps

First, let's set up our data. I've got a few readings here. Notice that they are in a "Year-Month-Day Hour:Minute:Second" format.

library(lubridate)

sensor_data <- data.frame(
  timestamp = c("2023-10-01 08:30:00", "2023-10-01 08:45:12", 
                "2023-10-01 09:15:00", "2023-10-02 02:00:00"),
  temp = c(22.1, 22.5, 23.0, 18.4),
  stringsAsFactors = FALSE
)

The magic of lubridate is that it provides functions that match the order of the elements in your string. Since my data is Year, then Month, then Day, followed by hours, minutes, and seconds, I'll use ymd_hms().

sensor_data$timestamp <- ymd_hms(sensor_data$timestamp)

Fixing my parsing blunder

Wait, I actually messed up. When I first wrote this script, I tried to use ymd() because I only cared about the date. But when I ran it, R stripped out all the time information, leaving me with just 2023-10-01. I lost the precision I needed for the interval calculations.

If you ever see your time data suddenly "truncate" after a conversion, check your function. ymd() is for dates; ymd_hms() is for date-times. I've corrected it above, and now sensor_data$timestamp is a proper POSIXct object that preserves the exact second the sensor fired.

Measuring the gaps between pings

Now I want to know the time elapsed between each reading. In base R, subtracting dates gives you a difftime object, which can be annoying to work with if you want a specific unit (like seconds or minutes).

I'll use interval() to create a span of time between the first and second readings, and then wrap that in as.duration() to make it easy to convert to a numeric value.

# Let's find the gap between the first two readings
start_time <- sensor_data$timestamp[1]
end_time <- sensor_data$timestamp[2]

gap <- interval(start_time, end_time)
duration_minutes <- as.duration(gap) / 60

print(duration_minutes) 
# Result: 15.2 minutes

I prefer interval because it represents a specific period of time on the calendar, whereas duration is just a length of time. It's a subtle distinction, but it matters when you start dealing with daylight savings time shifts.

Finding the peak activity hour

Finally, let's say we want to group these readings by the hour of the day to see when the sensor is most active. lubridate makes this trivial with "component" functions. Instead of complex formatting strings, you just use hour().

sensor_data$hour_of_day <- hour(sensor_data$timestamp)

# Now we can easily see the hours
print(sensor_data[, c("timestamp", "hour_of_day")])

By extracting the hour into its own column, we can now use standard aggregation tools (like table() or dplyr) to find the peak windows. It's much cleaner than trying to parse the string manually or using strftime().




📋 Practical Task

Calculating Flight Durations for a Regional Airline

You have been given a small dataset of flight departures and arrivals. Your task is to calculate the total travel time for each flight in minutes.

flights <- data.frame(
  flight_id = c("AA101", "DL202", "UA303"),
  departure = c("2023-11-15 10:00:00", "2023-11-15 13:30:00", "2023-11-16 08:15:00"),
  arrival = c("2023-11-15 12:45:00", "2023-11-15 16:00:00", "2023-11-16 11:30:00"),
  stringsAsFactors = FALSE
)

Requirements:

  • Convert the departure and arrival columns into proper date-time objects using lubridate.
  • Create a new column called duration_min that stores the difference between arrival and departure in minutes.
  • Extract the day of the week for each departure and store it in a column called departure_day (Hint: use wday()).
  • Print the final data frame.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.