Chapter 6 Working with dates and times
This chapter provides an overview of working with dates and times, for example extracting year or month from a date, and converting characters to a date.
One of the main packages used to work with dates is {lubridate}.
More information can be found on the {lubridate} cheatsheet at the following link: https://www.rstudio.com/resources/cheatsheets/
Date vectors are just vectors of class double with an additional class attribute set as “Date”.
DfT_birthday <- lubridate::as_date("1919-08-14")
typeof(DfT_birthday)
#> [1] "double"
attributes(DfT_birthday)
#> $class
#> [1] "Date"If we remove the class using unclass() we can reveal the value of the double, which is the number of days since “1970-01-01”3, since DfT’s birthday is before this date, the double is negative.
unclass(DfT_birthday)
#> [1] -18403This chapter will be using the road accident data set:
| acc_index | Date | Police_Force | Day_of_Week | Time |
|---|---|---|---|---|
| 2017010001708 | 2017-08-05 | 1 | 7 | 1899-12-31 03:12:00 |
| 2017010009342 | 2017-01-01 | 1 | 1 | 1899-12-31 01:30:00 |
| 2017010009344 | 2017-01-01 | 1 | 1 | 1899-12-31 00:30:00 |
| 2017010009348 | 2017-01-01 | 1 | 1 | 1899-12-31 01:11:00 |
| 2017010009350 | 2017-01-01 | 1 | 1 | 1899-12-31 01:42:00 |
| 2017010009351 | 2017-01-01 | 1 | 1 | 1899-12-31 03:31:00 |
6.1 Working with dates
6.1.1 Converting a character to a date
In R, dates can be converted to a specific date variable type in order to use the variable as a date.
Having a variable as a date means that you can:
- extract the different elements of the date (year, month etc.)
- calculate differences between dates
This can be done in the following way:
- Identify the order of the year, month, day and use the appropriate function (ymd, mdy, dmy etc.)
# convert date to date object
# check class of date
class(road_accidents$Date1)
#> [1] "character"
# look at the date variable and see what order it is in (year-m-d)
# therefore use the ymd function
road_accidents$Date1 <- lubridate::ymd(road_accidents$Date1)
# now check class
class(road_accidents$Date1)
#> [1] "Date"6.1.2 Get year from date
Use the year function from {lubridate}:
road_accidents$Year <- lubridate::year(road_accidents$Date1)See Table 5.2 for output
6.1.3 Get month from date
Use the month function from {lubridate}:
road_accidents$Month <- lubridate::month(road_accidents$Date1)See Table 5.2 for output
6.1.4 Get day from date
Use the day function from {lubridate}:
road_accidents$Day <- lubridate::day(road_accidents$Date1)See Table 5.2 for output
6.1.5 Get weekday from date
Use the wday function from {lubridate} to get the weekday label:
road_accidents$weekday <- lubridate::wday(road_accidents$Date1)See Table 5.2 for output
6.1.6 Get quarter from date
Use the quarter function from {lubridate}:
road_accidents$Quarter <- lubridate::quarter(road_accidents$Date1)See Table 5.2 for output
| Date1 | Year | Quarter | Month | Day | weekday |
|---|---|---|---|---|---|
| 2017-08-05 | 2017 | 3 | 8 | 5 | 7 |
| 2017-01-01 | 2017 | 1 | 1 | 1 | 1 |
| 2017-01-01 | 2017 | 1 | 1 | 1 | 1 |
| 2017-01-01 | 2017 | 1 | 1 | 1 | 1 |
| 2017-01-01 | 2017 | 1 | 1 | 1 | 1 |
| 2017-01-01 | 2017 | 1 | 1 | 1 | 1 |
6.1.7 Find difference between two dates
| acc_index | Date1 | Date2 |
|---|---|---|
| 2017010001708 | 2017-08-05 | 2017-08-01 |
| 2017010009342 | 2017-01-01 | 2017-01-01 |
| 2017010009344 | 2017-01-01 | 2017-01-01 |
| 2017010009348 | 2017-01-01 | 2017-01-01 |
| 2017010009350 | 2017-01-01 | 2017-01-01 |
| 2017010009351 | 2017-01-01 | 2017-01-01 |
Use the as.duration function to find the duration between two dates. The duration to be measured can be specified:
- dhours
- dweeks
- ddays
- dminutes
- dyears
To find out the number of days difference, the as.duration function calculates the duration in seconds so the duration must be divided by the desired duration (ddays) to convert to duration in days.
road_accidents$date_diff <-
lubridate::as.duration(road_accidents$Date2 %--% road_accidents$Date1) / ddays(1)| acc_index | Date1 | Date2 | date_diff |
|---|---|---|---|
| 2017010001708 | 2017-08-05 | 2017-08-01 | 4 |
| 2017010009342 | 2017-01-01 | 2017-01-01 | 0 |
| 2017010009344 | 2017-01-01 | 2017-01-01 | 0 |
| 2017010009348 | 2017-01-01 | 2017-01-01 | 0 |
| 2017010009350 | 2017-01-01 | 2017-01-01 | 0 |
| 2017010009351 | 2017-01-01 | 2017-01-01 | 0 |
The %--% operator is used to define an interval. So, this code is calculating the duration of the interval between Date2 and Date1.
The number after ddays indicates by how many units the duration is (i.e. one day).
6.1.8 Convert month (integer to character)
{base} R has a useful function which takes the month numbers and converts them to the corresponding text.
road_accidents$Month_lab <- month.abb[road_accidents$Month]| acc_index | Date | Month | Month_lab |
|---|---|---|---|
| 2017010001708 | 2017-08-05 | 8 | Aug |
| 2017010009342 | 2017-01-01 | 1 | Jan |
| 2017010009344 | 2017-01-01 | 1 | Jan |
| 2017010009348 | 2017-01-01 | 1 | Jan |
| 2017010009350 | 2017-01-01 | 1 | Jan |
| 2017010009351 | 2017-01-01 | 1 | Jan |
6.1.9 Convert month (character to integer)
{base} R has a useful function which takes the month text and converts them to the corresponding number.
road_accidents$Month <- match(road_accidents$Month_lab,month.abb)| acc_index | Date | Month | Month_lab |
|---|---|---|---|
| 2017010001708 | 2017-08-05 | 8 | Aug |
| 2017010009342 | 2017-01-01 | 1 | Jan |
| 2017010009344 | 2017-01-01 | 1 | Jan |
| 2017010009348 | 2017-01-01 | 1 | Jan |
| 2017010009350 | 2017-01-01 | 1 | Jan |
| 2017010009351 | 2017-01-01 | 1 | Jan |
6.1.10 Merge separate date information into a date
The {lubridate} package can be used in conjunction with the paste function to combine columns separate date information (e.g. year, month, day) into one date variable.
road_accidents$date <-
paste(road_accidents$Year, road_accidents$Month, road_accidents$Day, sep="-") %>%
ymd()%>%
as.Date()| acc_index | Date | Year | Month | Day | date |
|---|---|---|---|---|---|
| 2017010001708 | 2017-08-05 | 2017 | 8 | 5 | 2017-08-05 |
| 2017010009342 | 2017-01-01 | 2017 | 1 | 1 | 2017-01-01 |
| 2017010009344 | 2017-01-01 | 2017 | 1 | 1 | 2017-01-01 |
| 2017010009348 | 2017-01-01 | 2017 | 1 | 1 | 2017-01-01 |
| 2017010009350 | 2017-01-01 | 2017 | 1 | 1 | 2017-01-01 |
| 2017010009351 | 2017-01-01 | 2017 | 1 | 1 | 2017-01-01 |
6.2 Working with date-times
A date-time stores date and time information.
6.2.1 Converting a character to a date-time
This is similar to converting a character to a date as mentioned above.
This can be done in the following way:
- Identify the order of the year, month, day, and time elements (hour, minute and second or just hour and minute) and use the appropriate function (ymd, mdy, dmy etc.)
# convert date to date object
# look at the date variable and see what order it is in (year-m-d, hms "2017-11-28 14:00)
# therefore use the ymd_hm
road_accidents$Date_time1 <- lubridate::ymd_hm(road_accidents$Date_time)6.2.2 Extract date from date time variable
Use the date function to extract the date from a date time variable.
The year/month/day information can then be extracted from the date using the code examples above.
road_accidents$Date2 <- lubridate::date(road_accidents$Date_time)6.2.3 Convert character to hms (time) variable
Convert time as character into a hms variable so the variable can manipulated as a time object.
This can be done using the {hms} package.
road_accidents$Time <- hms::as_hms(road_accidents$Time)6.2.4 Extract hour from time
Use the hour function from the {lubridate} package to extract hour information.
road_accidents$hour <- lubridate::hour(road_accidents$Time)See Table 5.8 for output
6.2.5 Extract minute from time
Use the minute function from the {lubridate} package to extract minute information.
road_accidents$minute <- lubridate::minute(road_accidents$Time)See Table 5.8 for output
6.2.6 Extract second from time
Use the second function from the {lubridate} package to extract second information.
road_accidents$second <- lubridate::second(road_accidents$Time)See Table 5.8 for output
| acc_index | Time | hour | minute | second |
|---|---|---|---|---|
| 2017010001708 | 03:12:00 | 3 | 12 | 0 |
| 2017010009342 | 01:30:00 | 1 | 30 | 0 |
| 2017010009344 | 00:30:00 | 0 | 30 | 0 |
| 2017010009348 | 01:11:00 | 1 | 11 | 0 |
| 2017010009350 | 01:42:00 | 1 | 42 | 0 |
| 2017010009351 | 03:31:00 | 3 | 31 | 0 |
6.2.7 Merge separate time information into one variable
Hour, minute and second variables can be merged to create a time variable, and then converted to hms.
# merge seperate time information
road_accidents$time2 <- paste(road_accidents$hour,road_accidents$minute, road_accidents$second, sep=":")# convert to hms
road_accidents$time3 <- hms::as_hms(road_accidents$time2)| acc_index | hour | minute | second | time2 |
|---|---|---|---|---|
| 2017010001708 | 3 | 12 | 0 | 3:12:0 |
| 2017010009342 | 1 | 30 | 0 | 1:30:0 |
| 2017010009344 | 0 | 30 | 0 | 0:30:0 |
| 2017010009348 | 1 | 11 | 0 | 1:11:0 |
| 2017010009350 | 1 | 42 | 0 | 1:42:0 |
| 2017010009351 | 3 | 31 | 0 | 3:31:0 |
6.2.8 find the difference between two times
Use the {base} r difftime function to find the difference between two times.
Note: this can also be used to find the difference in days or weeks.
Also note: the object must be hms/date to be able to calculate the difference.
time_first <- hms::as.hms("11:00:00")
#> Warning: `as.hms()` was deprecated in hms 0.5.0.
#> ℹ Please use `as_hms()` instead.
time_second <- hms::as.hms("11:05:00")
difference <- difftime(time_first, time_second, "mins" )
difference
#> Time difference of -5 minsChange the unit of measurement to get different time differences (for days and weeks you’ll need a date rather than a hms).
Units: “secs”, “mins”, “hours”, “days”, “weeks”
a special date known as the Unix Epoch↩︎