Chapter 15 Dates and Times in R
15.1 What makes dates and times special
Dates and times can be a headache to work with. They may look just like numbers, but they don’t follow regular number rules. Here’s just a handful of things that make dates and times different:
- There’s no 61 after 60 when working with seconds and minutes;
- There’s no 25 after 24 when working with hours;
- There’s no 13 after 12 when working with months;
- Most years are 365-days long, but some are 366-days long;
- The same time means something different depending on the time zone;
- The same time means something different between standard and daylight savings time. And daylight savings time starts on a different day each year.
Keeping track of these rules manually would be a nightmare, especially when working with large datasets. In this Chapter we’re going to learn how to reproducibly deal with dates and times in R by treating these data types as the special kind that they are.
15.2 Definitions
Let’s start with some definitions that I’ll use throughout this Chapter:
- Date: this type of data contains information on day, month, and year;
- Time: this type of data contains information on hour, minute, and second;
- Timestamp: this type of data contains information on both date and time (day, month, year, hour, minute, second);
- Date-time: a generic term I use to refer to anything that is either a date, a time, or a timestamp.
15.3 Under the hood
As you may remember from Chapter 4, Excel stores dates and times in a spreadsheet as numbers. While what you see may be something of the format “2021-04-15”, the actual data stored under the hood is a number: specifically, the number of days between a reference date (which is 12/31/1899 on Windows and 12/31/1903 on Mac) and the date in the spreadsheet. In R, something similar happens. Base R has two basic classes for date/times, called POSIXct
and POSIXlt
. POSIXct
is the number of seconds since 1/1/1970 00:00:00 (this can be negative for dates before that day, so any dates are supported). POSIXlt
is a named list of vectors representing second, minute, hour, day of the month, months since January, years since 1900, day of the week, day of the year, and a flag defining whether it’s daylight savings time or not. For instance:
## [1] "character"
If I just write out a date in quotes, this is still just a character string.
## [1] "POSIXct" "POSIXt"
## [1] "2021-04-15 PDT"
But if I convert that character string into POSIXct, now R understands it is a date. What is displayed is the date in my current time zone (which R knows):
## [1] "America/Los_Angeles"
But what’s actually hiding under that date is the number of seconds from 1/1/1970. Let’s see what happens if I convert my date to POSIXlt
instead:
## [1] "POSIXlt" "POSIXt"
## [1] "2021-04-15 PDT"
What’s displayed doesn’t change, but the way R is storing the information under the hood is different.
You may have noticed that each time I converted to POSIXct
or POSIXlt
R also added the class POSIXt
to the object. POSIXt
is a class that inherits some properties from both POSIXct
and POSIXlt
, and it makes operations between the two possible.
Here is how to do the same thing with a date-time string:
## [1] "2021-04-15 13:20:00 PDT"
## [1] "2021-04-15 13:20:00 PDT"
Besides POSIXct
and POSIXlt
, R also support a data type called Date
. This is equivalent to Excel’s handling of dates, i.e., the number of days since 1/1/1970:
## [1] "2021-04-15"
This data type makes no assumptions about time zones. However, it can only support dates, not times:
## [1] "2021-04-15"
When we convert a date-time string into Date
, the time information is lost.
What if our date was in a different format than “2021-04-15”?
## Error in charToDate(x): character string is not in a standard unambiguous format
## Error in as.POSIXlt.character(x, tz, ...): character string is not in a standard unambiguous format
## Error in as.POSIXlt.character("04/15/2021"): character string is not in a standard unambiguous format
None of the functions above work because they can’t understand the format of the date. To make this work, we would have to give R a template of how the object is formatted. In our case, the format is “month/day/4-digit year” which is encoded as %m/%d/%Y
:
## [1] "2021-04-15"
## [1] "2021-04-15 PDT"
## [1] "2021-04-15 PDT"
What happens if we want to do some calculations on dates? For example, we want to know how many days went by between two dates. If our dates are formatted using a different data type, we may get some unexpected results:
## Warning: Incompatible methods ("-.Date", "-.POSIXt") for "-"
## [1] "-4429200-12-09"
## Warning: Incompatible methods ("-.POSIXt", "-.Date") for "-"
## Error in d2 - d3: non-numeric argument to binary operator
## Warning: Incompatible methods ("-.Date", "-.POSIXt") for "-"
## [1] "-4429200-12-09"
## Time difference of -1 days
## Warning: Incompatible methods ("-.POSIXt", "-.Date") for "-"
## [1] "2021-04-14 18:47:46 PDT"
Only one of the calculations above (d1 - d2
, where we are subtracting a POSIXlt
from a POSIXct
) worked and returned the right output. All the other ones returned weird outputs and a warning that the methods are incompatible.
The ones above are just a few examples to demonstrate how working with dates and times in R can still be complicated even using dedicated data types available within base R.
15.4 The lubridate
package
Working with dates and times in R becomes a whole lot easier when using the lubridate
package. lubridate
is part of the tidyverse
and it is meant to make working with dates and time as straightforward as possible. For one, functions in lubridate
are designed to behave consistently regardless of the underlying object. No need to keep track of what functions we can or cannot use on different date-time objects: the same handful of function work predictably on all of them. Using lubridate
does not mean foregoing base R’s handling of date-time objects: the package works nicely with built-in objects, it just makes them more user-friendly. Let’s look at some of the functionalities of lubridate.
15.4.1 Parsing dates and times
lubridate
comes with a suite of different functions to parse (i.e., correctly interpret the components of) dates, times, and timestamp. These functions are:
Depending on what format our input data is in, all we need to do is pick the correct function to convert our string into a date-time object:
## [1] "2021-04-15"
## [1] "2021-04-15"
## [1] "2021-04-15"
Note that all of these functions return the same identical output: the output format is always yyyy-mm-dd
and the output data type is always Date
.
## [1] "Date"
## [1] "Date"
## [1] "Date"
Let’s try with some timestamps:
# This string follows the format "year, month, day, hour, minute, second",
# so we use ymd_hms()
ymd_hms("2021-04-15 13:53:00")
## [1] "2021-04-15 13:53:00 UTC"
## [1] "2021-04-15 13:53:00 UTC"
# This string follows the format "month, day, year, hour, minute", so we use mdy_hm()
mdy_hm("4/15/2021 13:53")
## [1] "2021-04-15 13:53:00 UTC"
Again, the output format is always the same and the output class is too (this time it’s POSIXct
because there’s a time component in addition to the date):
## [1] "POSIXct" "POSIXt"
## [1] "POSIXct" "POSIXt"
## [1] "POSIXct" "POSIXt"
What happens if we use a function that doesn’t match the format we are providing in input?
## Warning: All formats failed to parse. No formats found.
## [1] NA
The output is NA
and we get a warning that the date failed to parse. That is because ymd()
is expecting a year, a month, and a day only; instead, we are giving it a full timestamp (year, month, day, hour, minute, second).
## Warning: All formats failed to parse. No formats found.
## [1] NA
This one failed because ymd_hms()
is expecting the elements in this order: year, month, day, hour, minute, second, but we are giving it in a different order (month, day, year, hour, minute, second). So, whenever you get the warning, All formats failed to parse. No formats found.
you’ll know that you either passed more components than the function expected, fewer components than the function expected, or you passed them in the wrong order.
One misconception that I frequently see is that people tend to think that the different functions we’ve seen (ymd()
, mdy()
, dmy()
, etc.) are used to tell lubridate
what format we want in output; but actually, the output returned is always the same. Those different functions exist so that can choose the appropriate function to match the format of our input, so that the string can be parsed correctly.
15.4.2 Extracting components of a date-time object
The following functions in lubridate
let you extract components of a date-time object:
## [1] 15
## [1] 4
## [1] 2021
## [1] 13
## [1] 56
## [1] 0
15.4.3 Time zones
By default, when we create a new timestamp with lubridate
, it will be assumed to be in UTC (Coordinated Universal Time):
## [1] "2021-04-15 13:56:00 UTC"
What if the timestamp is actually in a different time zone than that? We can use the argument tz
to specify what time zone the data are in when we create the object. For a list of available time zones, we can look up:
## [1] "Africa/Abidjan" "Africa/Accra"
## [3] "Africa/Addis_Ababa" "Africa/Algiers"
## [5] "Africa/Asmara" "Africa/Asmera"
## [7] "Africa/Bamako" "Africa/Bangui"
## [9] "Africa/Banjul" "Africa/Bissau"
## [11] "Africa/Blantyre" "Africa/Brazzaville"
## [13] "Africa/Bujumbura" "Africa/Cairo"
## [15] "Africa/Casablanca" "Africa/Ceuta"
## [17] "Africa/Conakry" "Africa/Dakar"
## [19] "Africa/Dar_es_Salaam" "Africa/Djibouti"
## [21] "Africa/Douala" "Africa/El_Aaiun"
## [23] "Africa/Freetown" "Africa/Gaborone"
## [25] "Africa/Harare" "Africa/Johannesburg"
## [27] "Africa/Juba" "Africa/Kampala"
## [29] "Africa/Khartoum" "Africa/Kigali"
## [31] "Africa/Kinshasa" "Africa/Lagos"
## [33] "Africa/Libreville" "Africa/Lome"
## [35] "Africa/Luanda" "Africa/Lubumbashi"
## [37] "Africa/Lusaka" "Africa/Malabo"
## [39] "Africa/Maputo" "Africa/Maseru"
## [41] "Africa/Mbabane" "Africa/Mogadishu"
## [43] "Africa/Monrovia" "Africa/Nairobi"
## [45] "Africa/Ndjamena" "Africa/Niamey"
## [47] "Africa/Nouakchott" "Africa/Ouagadougou"
## [49] "Africa/Porto-Novo" "Africa/Sao_Tome"
## [51] "Africa/Timbuktu" "Africa/Tripoli"
## [53] "Africa/Tunis" "Africa/Windhoek"
## [55] "America/Adak" "America/Anchorage"
## [57] "America/Anguilla" "America/Antigua"
## [59] "America/Araguaina" "America/Argentina/Buenos_Aires"
## [61] "America/Argentina/Catamarca" "America/Argentina/ComodRivadavia"
## [63] "America/Argentina/Cordoba" "America/Argentina/Jujuy"
## [65] "America/Argentina/La_Rioja" "America/Argentina/Mendoza"
## [67] "America/Argentina/Rio_Gallegos" "America/Argentina/Salta"
## [69] "America/Argentina/San_Juan" "America/Argentina/San_Luis"
## [71] "America/Argentina/Tucuman" "America/Argentina/Ushuaia"
## [73] "America/Aruba" "America/Asuncion"
## [75] "America/Atikokan" "America/Atka"
## [77] "America/Bahia" "America/Bahia_Banderas"
## [79] "America/Barbados" "America/Belem"
## [81] "America/Belize" "America/Blanc-Sablon"
## [83] "America/Boa_Vista" "America/Bogota"
## [85] "America/Boise" "America/Buenos_Aires"
## [87] "America/Cambridge_Bay" "America/Campo_Grande"
## [89] "America/Cancun" "America/Caracas"
## [91] "America/Catamarca" "America/Cayenne"
## [93] "America/Cayman" "America/Chicago"
## [95] "America/Chihuahua" "America/Ciudad_Juarez"
## [97] "America/Coral_Harbour" "America/Cordoba"
## [99] "America/Costa_Rica" "America/Creston"
## [101] "America/Cuiaba" "America/Curacao"
## [103] "America/Danmarkshavn" "America/Dawson"
## [105] "America/Dawson_Creek" "America/Denver"
## [107] "America/Detroit" "America/Dominica"
## [109] "America/Edmonton" "America/Eirunepe"
## [111] "America/El_Salvador" "America/Ensenada"
## [113] "America/Fort_Nelson" "America/Fort_Wayne"
## [115] "America/Fortaleza" "America/Glace_Bay"
## [117] "America/Godthab" "America/Goose_Bay"
## [119] "America/Grand_Turk" "America/Grenada"
## [121] "America/Guadeloupe" "America/Guatemala"
## [123] "America/Guayaquil" "America/Guyana"
## [125] "America/Halifax" "America/Havana"
## [127] "America/Hermosillo" "America/Indiana/Indianapolis"
## [129] "America/Indiana/Knox" "America/Indiana/Marengo"
## [131] "America/Indiana/Petersburg" "America/Indiana/Tell_City"
## [133] "America/Indiana/Vevay" "America/Indiana/Vincennes"
## [135] "America/Indiana/Winamac" "America/Indianapolis"
## [137] "America/Inuvik" "America/Iqaluit"
## [139] "America/Jamaica" "America/Jujuy"
## [141] "America/Juneau" "America/Kentucky/Louisville"
## [143] "America/Kentucky/Monticello" "America/Knox_IN"
## [145] "America/Kralendijk" "America/La_Paz"
## [147] "America/Lima" "America/Los_Angeles"
## [149] "America/Louisville" "America/Lower_Princes"
## [151] "America/Maceio" "America/Managua"
## [153] "America/Manaus" "America/Marigot"
## [155] "America/Martinique" "America/Matamoros"
## [157] "America/Mazatlan" "America/Mendoza"
## [159] "America/Menominee" "America/Merida"
## [161] "America/Metlakatla" "America/Mexico_City"
## [163] "America/Miquelon" "America/Moncton"
## [165] "America/Monterrey" "America/Montevideo"
## [167] "America/Montreal" "America/Montserrat"
## [169] "America/Nassau" "America/New_York"
## [171] "America/Nipigon" "America/Nome"
## [173] "America/Noronha" "America/North_Dakota/Beulah"
## [175] "America/North_Dakota/Center" "America/North_Dakota/New_Salem"
## [177] "America/Nuuk" "America/Ojinaga"
## [179] "America/Panama" "America/Pangnirtung"
## [181] "America/Paramaribo" "America/Phoenix"
## [183] "America/Port-au-Prince" "America/Port_of_Spain"
## [185] "America/Porto_Acre" "America/Porto_Velho"
## [187] "America/Puerto_Rico" "America/Punta_Arenas"
## [189] "America/Rainy_River" "America/Rankin_Inlet"
## [191] "America/Recife" "America/Regina"
## [193] "America/Resolute" "America/Rio_Branco"
## [195] "America/Rosario" "America/Santa_Isabel"
## [197] "America/Santarem" "America/Santiago"
## [199] "America/Santo_Domingo" "America/Sao_Paulo"
## [201] "America/Scoresbysund" "America/Shiprock"
## [203] "America/Sitka" "America/St_Barthelemy"
## [205] "America/St_Johns" "America/St_Kitts"
## [207] "America/St_Lucia" "America/St_Thomas"
## [209] "America/St_Vincent" "America/Swift_Current"
## [211] "America/Tegucigalpa" "America/Thule"
## [213] "America/Thunder_Bay" "America/Tijuana"
## [215] "America/Toronto" "America/Tortola"
## [217] "America/Vancouver" "America/Virgin"
## [219] "America/Whitehorse" "America/Winnipeg"
## [221] "America/Yakutat" "America/Yellowknife"
## [223] "Antarctica/Casey" "Antarctica/Davis"
## [225] "Antarctica/DumontDUrville" "Antarctica/Macquarie"
## [227] "Antarctica/Mawson" "Antarctica/McMurdo"
## [229] "Antarctica/Palmer" "Antarctica/Rothera"
## [231] "Antarctica/South_Pole" "Antarctica/Syowa"
## [233] "Antarctica/Troll" "Antarctica/Vostok"
## [235] "Arctic/Longyearbyen" "Asia/Aden"
## [237] "Asia/Almaty" "Asia/Amman"
## [239] "Asia/Anadyr" "Asia/Aqtau"
## [241] "Asia/Aqtobe" "Asia/Ashgabat"
## [243] "Asia/Ashkhabad" "Asia/Atyrau"
## [245] "Asia/Baghdad" "Asia/Bahrain"
## [247] "Asia/Baku" "Asia/Bangkok"
## [249] "Asia/Barnaul" "Asia/Beirut"
## [251] "Asia/Bishkek" "Asia/Brunei"
## [253] "Asia/Calcutta" "Asia/Chita"
## [255] "Asia/Choibalsan" "Asia/Chongqing"
## [257] "Asia/Chungking" "Asia/Colombo"
## [259] "Asia/Dacca" "Asia/Damascus"
## [261] "Asia/Dhaka" "Asia/Dili"
## [263] "Asia/Dubai" "Asia/Dushanbe"
## [265] "Asia/Famagusta" "Asia/Gaza"
## [267] "Asia/Harbin" "Asia/Hebron"
## [269] "Asia/Ho_Chi_Minh" "Asia/Hong_Kong"
## [271] "Asia/Hovd" "Asia/Irkutsk"
## [273] "Asia/Istanbul" "Asia/Jakarta"
## [275] "Asia/Jayapura" "Asia/Jerusalem"
## [277] "Asia/Kabul" "Asia/Kamchatka"
## [279] "Asia/Karachi" "Asia/Kashgar"
## [281] "Asia/Kathmandu" "Asia/Katmandu"
## [283] "Asia/Khandyga" "Asia/Kolkata"
## [285] "Asia/Krasnoyarsk" "Asia/Kuala_Lumpur"
## [287] "Asia/Kuching" "Asia/Kuwait"
## [289] "Asia/Macao" "Asia/Macau"
## [291] "Asia/Magadan" "Asia/Makassar"
## [293] "Asia/Manila" "Asia/Muscat"
## [295] "Asia/Nicosia" "Asia/Novokuznetsk"
## [297] "Asia/Novosibirsk" "Asia/Omsk"
## [299] "Asia/Oral" "Asia/Phnom_Penh"
## [301] "Asia/Pontianak" "Asia/Pyongyang"
## [303] "Asia/Qatar" "Asia/Qostanay"
## [305] "Asia/Qyzylorda" "Asia/Rangoon"
## [307] "Asia/Riyadh" "Asia/Saigon"
## [309] "Asia/Sakhalin" "Asia/Samarkand"
## [311] "Asia/Seoul" "Asia/Shanghai"
## [313] "Asia/Singapore" "Asia/Srednekolymsk"
## [315] "Asia/Taipei" "Asia/Tashkent"
## [317] "Asia/Tbilisi" "Asia/Tehran"
## [319] "Asia/Tel_Aviv" "Asia/Thimbu"
## [321] "Asia/Thimphu" "Asia/Tokyo"
## [323] "Asia/Tomsk" "Asia/Ujung_Pandang"
## [325] "Asia/Ulaanbaatar" "Asia/Ulan_Bator"
## [327] "Asia/Urumqi" "Asia/Ust-Nera"
## [329] "Asia/Vientiane" "Asia/Vladivostok"
## [331] "Asia/Yakutsk" "Asia/Yangon"
## [333] "Asia/Yekaterinburg" "Asia/Yerevan"
## [335] "Atlantic/Azores" "Atlantic/Bermuda"
## [337] "Atlantic/Canary" "Atlantic/Cape_Verde"
## [339] "Atlantic/Faeroe" "Atlantic/Faroe"
## [341] "Atlantic/Jan_Mayen" "Atlantic/Madeira"
## [343] "Atlantic/Reykjavik" "Atlantic/South_Georgia"
## [345] "Atlantic/St_Helena" "Atlantic/Stanley"
## [347] "Australia/ACT" "Australia/Adelaide"
## [349] "Australia/Brisbane" "Australia/Broken_Hill"
## [351] "Australia/Canberra" "Australia/Currie"
## [353] "Australia/Darwin" "Australia/Eucla"
## [355] "Australia/Hobart" "Australia/LHI"
## [357] "Australia/Lindeman" "Australia/Lord_Howe"
## [359] "Australia/Melbourne" "Australia/North"
## [361] "Australia/NSW" "Australia/Perth"
## [363] "Australia/Queensland" "Australia/South"
## [365] "Australia/Sydney" "Australia/Tasmania"
## [367] "Australia/Victoria" "Australia/West"
## [369] "Australia/Yancowinna" "Brazil/Acre"
## [371] "Brazil/DeNoronha" "Brazil/East"
## [373] "Brazil/West" "Canada/Atlantic"
## [375] "Canada/Central" "Canada/Eastern"
## [377] "Canada/Mountain" "Canada/Newfoundland"
## [379] "Canada/Pacific" "Canada/Saskatchewan"
## [381] "Canada/Yukon" "CET"
## [383] "Chile/Continental" "Chile/EasterIsland"
## [385] "CST6CDT" "Cuba"
## [387] "EET" "Egypt"
## [389] "Eire" "EST"
## [391] "EST5EDT" "Etc/GMT"
## [393] "Etc/GMT-0" "Etc/GMT-1"
## [395] "Etc/GMT-10" "Etc/GMT-11"
## [397] "Etc/GMT-12" "Etc/GMT-13"
## [399] "Etc/GMT-14" "Etc/GMT-2"
## [401] "Etc/GMT-3" "Etc/GMT-4"
## [403] "Etc/GMT-5" "Etc/GMT-6"
## [405] "Etc/GMT-7" "Etc/GMT-8"
## [407] "Etc/GMT-9" "Etc/GMT+0"
## [409] "Etc/GMT+1" "Etc/GMT+10"
## [411] "Etc/GMT+11" "Etc/GMT+12"
## [413] "Etc/GMT+2" "Etc/GMT+3"
## [415] "Etc/GMT+4" "Etc/GMT+5"
## [417] "Etc/GMT+6" "Etc/GMT+7"
## [419] "Etc/GMT+8" "Etc/GMT+9"
## [421] "Etc/GMT0" "Etc/Greenwich"
## [423] "Etc/UCT" "Etc/Universal"
## [425] "Etc/UTC" "Etc/Zulu"
## [427] "Europe/Amsterdam" "Europe/Andorra"
## [429] "Europe/Astrakhan" "Europe/Athens"
## [431] "Europe/Belfast" "Europe/Belgrade"
## [433] "Europe/Berlin" "Europe/Bratislava"
## [435] "Europe/Brussels" "Europe/Bucharest"
## [437] "Europe/Budapest" "Europe/Busingen"
## [439] "Europe/Chisinau" "Europe/Copenhagen"
## [441] "Europe/Dublin" "Europe/Gibraltar"
## [443] "Europe/Guernsey" "Europe/Helsinki"
## [445] "Europe/Isle_of_Man" "Europe/Istanbul"
## [447] "Europe/Jersey" "Europe/Kaliningrad"
## [449] "Europe/Kiev" "Europe/Kirov"
## [451] "Europe/Kyiv" "Europe/Lisbon"
## [453] "Europe/Ljubljana" "Europe/London"
## [455] "Europe/Luxembourg" "Europe/Madrid"
## [457] "Europe/Malta" "Europe/Mariehamn"
## [459] "Europe/Minsk" "Europe/Monaco"
## [461] "Europe/Moscow" "Europe/Nicosia"
## [463] "Europe/Oslo" "Europe/Paris"
## [465] "Europe/Podgorica" "Europe/Prague"
## [467] "Europe/Riga" "Europe/Rome"
## [469] "Europe/Samara" "Europe/San_Marino"
## [471] "Europe/Sarajevo" "Europe/Saratov"
## [473] "Europe/Simferopol" "Europe/Skopje"
## [475] "Europe/Sofia" "Europe/Stockholm"
## [477] "Europe/Tallinn" "Europe/Tirane"
## [479] "Europe/Tiraspol" "Europe/Ulyanovsk"
## [481] "Europe/Uzhgorod" "Europe/Vaduz"
## [483] "Europe/Vatican" "Europe/Vienna"
## [485] "Europe/Vilnius" "Europe/Volgograd"
## [487] "Europe/Warsaw" "Europe/Zagreb"
## [489] "Europe/Zaporozhye" "Europe/Zurich"
## [491] "GB" "GB-Eire"
## [493] "GMT" "GMT-0"
## [495] "GMT+0" "GMT0"
## [497] "Greenwich" "Hongkong"
## [499] "HST" "Iceland"
## [501] "Indian/Antananarivo" "Indian/Chagos"
## [503] "Indian/Christmas" "Indian/Cocos"
## [505] "Indian/Comoro" "Indian/Kerguelen"
## [507] "Indian/Mahe" "Indian/Maldives"
## [509] "Indian/Mauritius" "Indian/Mayotte"
## [511] "Indian/Reunion" "Iran"
## [513] "Israel" "Jamaica"
## [515] "Japan" "Kwajalein"
## [517] "Libya" "MET"
## [519] "Mexico/BajaNorte" "Mexico/BajaSur"
## [521] "Mexico/General" "MST"
## [523] "MST7MDT" "Navajo"
## [525] "NZ" "NZ-CHAT"
## [527] "Pacific/Apia" "Pacific/Auckland"
## [529] "Pacific/Bougainville" "Pacific/Chatham"
## [531] "Pacific/Chuuk" "Pacific/Easter"
## [533] "Pacific/Efate" "Pacific/Enderbury"
## [535] "Pacific/Fakaofo" "Pacific/Fiji"
## [537] "Pacific/Funafuti" "Pacific/Galapagos"
## [539] "Pacific/Gambier" "Pacific/Guadalcanal"
## [541] "Pacific/Guam" "Pacific/Honolulu"
## [543] "Pacific/Johnston" "Pacific/Kanton"
## [545] "Pacific/Kiritimati" "Pacific/Kosrae"
## [547] "Pacific/Kwajalein" "Pacific/Majuro"
## [549] "Pacific/Marquesas" "Pacific/Midway"
## [551] "Pacific/Nauru" "Pacific/Niue"
## [553] "Pacific/Norfolk" "Pacific/Noumea"
## [555] "Pacific/Pago_Pago" "Pacific/Palau"
## [557] "Pacific/Pitcairn" "Pacific/Pohnpei"
## [559] "Pacific/Ponape" "Pacific/Port_Moresby"
## [561] "Pacific/Rarotonga" "Pacific/Saipan"
## [563] "Pacific/Samoa" "Pacific/Tahiti"
## [565] "Pacific/Tarawa" "Pacific/Tongatapu"
## [567] "Pacific/Truk" "Pacific/Wake"
## [569] "Pacific/Wallis" "Pacific/Yap"
## [571] "Poland" "Portugal"
## [573] "PRC" "PST8PDT"
## [575] "ROC" "ROK"
## [577] "Singapore" "Turkey"
## [579] "UCT" "Universal"
## [581] "US/Alaska" "US/Aleutian"
## [583] "US/Arizona" "US/Central"
## [585] "US/East-Indiana" "US/Eastern"
## [587] "US/Hawaii" "US/Indiana-Starke"
## [589] "US/Michigan" "US/Mountain"
## [591] "US/Pacific" "US/Samoa"
## [593] "UTC" "W-SU"
## [595] "WET" "Zulu"
## attr(,"Version")
## [1] "2023c"
Our time zone is “America/Denver”. Let’s specify that when creating our object:
## [1] "2021-04-15 13:56:00 MDT"
Notice that lubridate
knows that 2021-04-15 is during Daylight Savings Time, and it automatically assigns MDT instead of MST.
Now we can convert this object in whichever time zone we want. For instance, when it’s 13:56:00 in Logan, UT on April 15th 2021, what time is it in Rome, Italy?
## [1] "2021-04-15 21:56:00 CEST"
And what time is that in New York City?
## [1] "2021-04-15 15:56:00 EDT"
What if we didn’t mean to get the equivalent of “2021-04-15 13:56:00 MDT” in another time zone, but instead we wanted to keep the timestamp exactly as it is but set it in a different time zone? We can use force_tz()
:
## [1] "2021-04-15 13:56:00 MDT"
## [1] "2021-04-15 13:56:00 EDT"
15.4.4 Time spans
lubridate
works with three types of time spans:
- Periods are fixed amounts of time, ignoring any time irregularities;
- Durations are amounts of time that account for time irregularities such as leap years or months of different length;
- Intervals are stretches of time between a specific start date and end date.
Let’s look at a few examples to illustrate the difference between these. For example, we can get a period of N months by using the function months()
, and a duration of N months by using the function dmonths()
:
## [1] "Period"
## attr(,"package")
## [1] "lubridate"
## [1] "Duration"
## attr(,"package")
## [1] "lubridate"
## [1] "2021-06-15 13:56:00 MDT"
## [1] "2021-06-15 10:56:00 MDT"
Our dt
timestamp is in April. Adding a period of 2 months to dt
means simply changing the month component to June, leaving everything else unchanged. Adding a duration of 2 months to dt
means adding the average equivalent of 2 months in seconds (not all months have the same amount of seconds in them because the duration of a month changes between 28 and 31 days, so that’s why I specified “average”). That’s why the result when we add a 2-month duration to dt
is 3 hours earlier than when we add a 2-month period.
Periods and durations are useful for doing math with date-time objects. We can answer questions such as, what time will it be in 1 hour and 30 minutes?
## [1] "2021-04-15 15:26:00 MDT"
Or, say that we want to know what day of the week it was today, 3 years ago:
## [1] Sun
## Levels: Sun < Mon < Tue < Wed < Thu < Fri < Sat
Three years ago today was Sunday!
Unlike periods and durations, intervals are especially handy for some type of operations where it matters when exactly a time span takes place (not just how long it is). For example, say that we have a period that goes from January 19th, 2021 (our first class this semester) to April 27th, 2021 (our last class this semester):
# There are two equivalent ways to create an interval:
# Option 1
s <- interval(ymd("2021-01-19", tz = "America/Denver"), ymd("2021-04-27", tz = "America/Denver"))
# Option 2
s <- ymd("2021-01-19", tz = "America/Denver") %--% ymd("2021-04-27", tz = "America/Denver")
class(s)
## [1] "Interval"
## attr(,"package")
## [1] "lubridate"
We can get the start or end date of an interval as follows:
## [1] "2021-01-19 MST"
## [1] "2021-04-27 MDT"
We can check how long the interval is:
## [1] 8463600
We can check if any arbitrary date falls within that interval:
## [1] TRUE
## [1] FALSE
We can shift the interval up or down by a certain time span:
## [1] 2021-02-19 MST--2021-05-27 MDT
## [1] 2021-01-12 MST--2021-04-20 MDT
We can create multiple intervals and check whether they overlap:
i <- interval(ymd("2017-07-24", tz = "America/Denver"), ymd("2021-02-12", tz = "America/Denver"))
int_overlaps(i, s)
## [1] TRUE
15.5 References
- DateTime Classes in R: https://astrostatistics.psu.edu/su07/R/html/base/html/DateTimeClasses.html#:~:text=%22POSIXct%22%20is%20more%20convenient%20for,are%20available%20for%20both%20classes.
- Lubridate cheatsheet: https://rawgit.com/rstudio/cheatsheets/master/lubridate.pdf