Now you have learned numeric vectors, character vectors and logical vectors which are quite intuitive. In this section, we want to introduce two special formats of vectors in R which are dates and times. Dates and times belong to vectors because they only contain values of the same type.
a. Date class
Let’s first look at a vector in the date format. First, to get today’s date, you can use the
Sys.Date() function. Similarly, you can verify its class by using the
<- Sys.Date() today today#>  "2022-06-05" class(today) #>  "Date"
Looking at the output, we know that
today is a vector of the Date class. You may be wondering how are the dates stored in R. To get this information, you can use the
typeof() function on a date object.
typeof(today) #>  "double"
This may look a bit surprising to you. Indeed, dates objects are stored as numeric values (in “double” to be precise), representing the (signed) number of days that has passed since Jan 1, 1970 (The reference date in R). To get this information, you can convert it to a number by
as.numeric(today) #>  19148
Storing the dates as numbers make it handy to perform additions and subtractions. For example, you can use
today - 1 to get the date of yesterday, and use
today + 1 to get the date of tomorrow.
- 1 today #>  "2022-06-04" + 1 today #>  "2022-06-06"
The computation in R is done by adding or subtracting one to the number of days since Jan 1, 1970.
Although the output of
today looks similar to a string, you will get a character vector if you assign value(s) like
"2021-09-09" to a name. You you can verify its class by using
Of course, an error will show up if you try to do addition or subtraction operations on a character vector.
<- "2021-09-09" date_char class(date_char) - 1 date_char #> Error in date_char - 1: non-numeric argument to binary operator
You can also get the days of week, months, and quarters for a date using the functions
weekdays(today) months(today) quarters(today)
b. Converting between dates and strings
Now, you may be wondering what information we can extract out of an object of the date class. We can use the
format() function to convert a date class object into a string that contains various information about the date. First, let’s introduce a list of commonly used elements of dates and the corresponding conversion specification. A conversion specification is usually formed by
% followed by a single letter. The following table shows a list of common conversion specifications.
Then, for a Date class object, we can create a format string that containing any number of the conversion specifications in the previous table. The working mechanism of
format() is that it will scan through the format string, look for all the conversion specifications, and convert the conversion specifications into their corresponding values for the given date. Any character in the format string which is not part of a conversion specification is interpreted literally (and
%). Let’s see an example.
format(today, "Today is %A (%a for short), %b %d, %Y. It is also %m/%d/%Y") #>  "Today is Sunday (Sun for short), Jun 05, 2022. It is also 06/05/2022"
On the other hand, we can also convert a string back into a Date class object. To do that, you can use the
as.Date() function with the string along with the corresponding format string in the
fomat argument. You can also specify the
tryFormats argument, which contains a character vector with all possible formats to try.
<- as.Date("08-01-2021", format = "%m-%d-%Y") Aug Aug#>  "2021-08-01" class(Aug) #>  "Date"
Here, the value of
format corresponds to each part in string.
%m corresponds to
08, which is the month of the date.
%d corresponds to
01, which is the day of the date.
%Y corresponds to
2021, which is the year of the date. Now you have successfully converted the string into a vector of the Date class!
as.Date() function can be viewed as the inverse function of
format() when we use the same format string.
as.Date(format(today, format = "%m-%d-%Y"), format = "%m-%d-%Y")
Notice that the correspondence of the string and supplied format should follow the above table, otherwise you may get some unexpected result.
as.Date("08-01-2021", format = "%B-%d-%y") #wrong #>  NA as.Date("August-01-2021", format = "%B-%d-%y") #correct #>  "2020-08-01"
Here, you should use
August rather than
08 in string because
%B corresponds to full month, so you get
NA as the result.
In addition to use
- as the separator, you can also use
/ as the separator. If the separators used in the string and the format doesn’t match in
as.Date(), you will also get
NA as the result.
as.Date("08/01/2021", format = "%m/%d/%y") #>  "2020-08-01" as.Date("08/01/2021", format = "%m-%d-%y") #>  NA as.Date("08/01/2021", format = "%m-%d/%y") #>  NA
You can try different combinations by yourself. Here are some examples！
as.Date("01-03-2021", format = "%m-%d-%Y") #>  "2021-01-03" as.Date("01-03-2021", format = "%d-%m-%Y") #>  "2021-03-01" as.Date("Apr-03-2021", format = "%b-%d-%Y") #>  "2021-04-03" as.Date("09/October/97", format = "%d/%B/%y") #>  "1997-10-09" as.Date("2010-02-29", format = "%Y-%m-%d") #>  NA
It is worth noting that the last output is
NA, indicating that Feb 29, 2010 is not a valid date. That’s because only leap years have 29 days in February!
We can also construct date using the number of days since a reference date using the
origin argument in the
as.Date(10, origin = "2021-01-01") #10 days after 2021-01-01 #>  "2021-01-11"
Now, let’s introduce a very useful class named
difftime. From the name, you may be able to tell it is designed to represent time differences. Let’s see an example when we subtract between two dates objects.
<- as.Date("1970/01/01", format = "%Y/%m/%d") ref_date <- today - ref_date #the time difference between two dates days_diff days_diff#> Time difference of 19148 days class(days_diff) #>  "difftime"
To learn more about the
difftime class, let’s look at its structure.
str(days_diff) #> 'difftime' num 19148 #> - attr(*, "units")= chr "days"
You can see that it is stored as a number, with an attribute named
"units" and the value
"days". This attribute shows the units of the difference. To create a time difference in other units, you can use the
difftime() function and specify the
units argument to the desired units.
<- difftime(today, ref_date, units = "hours") hours_diff <- difftime(today, ref_date, units = "weeks")weeks_diff
You can also use the
as.difftime() function to help getting date. For example, to get the date of 10 weeks and 3 days from
today, you can use the following code.
<- as.difftime(10, units = "weeks") ten_week + ten_week + 3 today #>  "2022-08-17"
After talking about dates, it is natural to introduce how times are represented in R. Just like dates, let’s first get the time at the current moment using the
Sys.time() function. You can also check its class, internal storage type, and structure by the
<- Sys.time() now now#>  "2022-06-05 09:11:52 EDT" class(now) #>  "POSIXct" "POSIXt" typeof(now) #>  "double" str(now) #> POSIXct[1:1], format: "2022-06-05 09:11:52"
now is of class
POSIXct. The second element of
POSIXt, which is a parent class for class
POSIXct and class
PISIXlt. This parent class
POSIXt is used to allow operations such as subtraction to mix the two classes.
From the result of
typeof(now), we know that similar to dates, the
POSIXct class used to represent times is also stored as
double. Indeed, the class
POSIXct represents the (signed) number of seconds since the beginning of 1970 as a numeric vector.
You can also get the time of an hour ago or a minute later. Now, here the difference is in the unit of seconds instead of days for the date class.
- 3600 now #>  "2022-06-05 08:11:52 EDT" + 60 now #>  "2022-06-05 09:12:52 EDT"
Besides all the elements for dates you can use for the time class object, a list of other commonly used elements of times and the corresponding conversion specifications is summarized in the following table.
Just like dates, you can format the time into characters via the
format(now, "Hi! The current time in %Z (Time Zone) is %A (weekday), year %Y, month %m, day %d, hour %H, min %M, second %S. ") #>  "Hi! The current time in EDT (Time Zone) is Sunday (weekday), year 2022, month 06, day 05, hour 09, min 11, second 52. "
You can also display the time in a different time zone by setting the
tz argument in the
format(now, tz = "UTC") #Coordinated Universal Time #>  "2022-06-05 13:11:52" format(now, tz = "America/Los_Angeles") #Pacific Standard Time #>  "2022-06-05 06:11:52" format(now, tz = "America/New_York") #Eastern Standard Time #>  "2022-06-05 09:11:52" format(now, tz = "Europe/London") #Greenwich Mean Time #>  "2022-06-05 14:11:52"
To create a time object from a character, you can use the
as.POSIXlt() function with the optional
as.POSIXct("2021-09-21 13:14:15", format = "%Y-%m-%d %H:%M:%S") #>  "2021-09-21 13:14:15 EDT" as.POSIXct("13:14:15, Sep 21, 2021", format = "%H:%M:%S, %b %d, %Y") #>  "2021-09-21 13:14:15 EDT"
Similar as the difference of dates, the difference of two times is also an object of class
difftime. You can again use the
as.difftime() function to help with getting a time difference object in the given unit. For example, to get the time 2 days 3 hours and 4 minutes later, you can use the following.
+ as.difftime(2, units = "days") + as.difftime(3, units = "hours") + as.difftime(4, units = "mins") now #>  "2022-06-07 12:15:52 EDT"
From year 1900 to year 2021 (inclusive), calculate the number of leap years. (Hint: for a leap year, February has 29 days instead of 28. The value of
as.Date("2010-02-29", format = "%Y-%m-%d")is
x <- as.Date("69-01-01", format = "%y-%m-%d")and
y <- as.Date("68-12-31", format = "%y-%m-%d"), what is
x - y? Please think about the answer first, then try it in R.
What’s the date of the day that is 1000 days later than Feb 14, 2021.
What’s the time that is 1 year, 2 days, 3 hours, 4 minutes, and 5 seconds past 8:15pm on July 4, 2021.