CINXE.COM
17 Dates and times – R for Data Science (2e)
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta charset="utf-8"> <meta name="generator" content="quarto-1.6.41"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> <meta name="author" content="Hadley Wickham, Mine Çetinkaya-Rundel, and Garrett Grolemund"> <title>17 Dates and times – R for Data Science (2e)</title> <style> code{white-space: pre-wrap;} span.smallcaps{font-variant: small-caps;} div.columns{display: flex; gap: min(4vw, 1.5em);} div.column{flex: auto; overflow-x: auto;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} ul.task-list{list-style: none;} ul.task-list li input[type="checkbox"] { width: 0.8em; margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ vertical-align: middle; } /* CSS for syntax highlighting */ pre > code.sourceCode { white-space: pre; position: relative; } pre > code.sourceCode > span { line-height: 1.25; } pre > code.sourceCode > span:empty { height: 1.2em; } .sourceCode { overflow: visible; } code.sourceCode > span { color: inherit; text-decoration: inherit; } div.sourceCode { margin: 1em 0; } pre.sourceCode { margin: 0; } @media screen { div.sourceCode { overflow: auto; } } @media print { pre > code.sourceCode { white-space: pre-wrap; } pre > code.sourceCode > span { display: inline-block; text-indent: -5em; padding-left: 5em; } } pre.numberSource code { counter-reset: source-line 0; } pre.numberSource code > span { position: relative; left: -4em; counter-increment: source-line; } pre.numberSource code > span > a:first-child::before { content: counter(source-line); position: relative; left: -1em; text-align: right; vertical-align: baseline; border: none; display: inline-block; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; padding: 0 4px; width: 4em; } pre.numberSource { margin-left: 3em; padding-left: 4px; } div.sourceCode { } @media screen { pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } } </style> <script src="site_libs/quarto-nav/quarto-nav.js"></script> <script src="site_libs/quarto-nav/headroom.min.js"></script> <script src="site_libs/clipboard/clipboard.min.js"></script> <script src="site_libs/quarto-search/autocomplete.umd.js"></script> <script src="site_libs/quarto-search/fuse.min.js"></script> <script src="site_libs/quarto-search/quarto-search.js"></script> <meta name="quarto:offset" content="./"> <link href="./missing-values.html" rel="next"> <link href="./factors.html" rel="prev"> <link href="./cover.jpg" rel="icon" type="image/jpeg"> <script src="site_libs/quarto-html/quarto.js"></script> <script src="site_libs/quarto-html/popper.min.js"></script> <script src="site_libs/quarto-html/tippy.umd.min.js"></script> <script src="site_libs/quarto-html/anchor.min.js"></script> <link href="site_libs/quarto-html/tippy.css" rel="stylesheet"> <link href="site_libs/quarto-html/quarto-syntax-highlighting-48ffa3e5b9d089919c6712c39e5b00f2.css" rel="stylesheet" id="quarto-text-highlighting-styles"> <script src="site_libs/bootstrap/bootstrap.min.js"></script> <link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> <link href="site_libs/bootstrap/bootstrap-8ce0fe0cac6e1f664755c487f6c42e13.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light"><script id="quarto-search-options" type="application/json">{ "location": "sidebar", "copy-button": false, "collapse-after": 3, "panel-placement": "start", "type": "textbox", "limit": 50, "keyboard-shortcut": [ "f", "/", "s" ], "show-item-context": false, "language": { "search-no-results-text": "No results", "search-matching-documents-text": "matching documents", "search-copy-link-title": "Copy link to search", "search-hide-matches-text": "Hide additional matches", "search-more-match-text": "more match in this document", "search-more-matches-text": "more matches in this document", "search-clear-button-title": "Clear", "search-text-placeholder": "", "search-detached-cancel-button-title": "Cancel", "search-submit-button-title": "Submit", "search-label": "Search" } }</script><script defer="" data-domain="r4ds.hadley.nz" src="https://plausible.io/js/plausible.js"></script> </head> <body class="nav-sidebar floating"> <div id="quarto-search-results"></div> <header id="quarto-header" class="headroom fixed-top"><nav class="quarto-secondary-nav"><div class="container-fluid d-flex"> <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" role="button" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> <i class="bi bi-layout-text-sidebar-reverse"></i> </button> <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="./transform.html">Transform</a></li><li class="breadcrumb-item"><a href="./datetimes.html"><span class="chapter-number">17</span> <span class="chapter-title">Dates and times</span></a></li></ol></nav> <a class="flex-grow-1" role="navigation" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> </a> <button type="button" class="btn quarto-search-button" aria-label="Search" onclick="window.quartoOpenSearch();"> <i class="bi bi-search"></i> </button> </div> </nav></header><!-- content --><div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article"> <!-- sidebar --> <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal quarto-sidebar-collapse-item sidebar-navigation floating overflow-auto"><div class="pt-lg-2 mt-2 text-left sidebar-header"> <div class="sidebar-title mb-0 py-0"> <a href="./">R for Data Science (2e)</a> <div class="sidebar-tools-main"> <a href="https://github.com/hadley/r4ds/" title="Source Code" class="quarto-navigation-tool px-1" aria-label="Source Code"><i class="bi bi-github"></i></a> <a href="" class="quarto-reader-toggle quarto-navigation-tool px-1" onclick="window.quartoToggleReader(); return false;" title="Toggle reader mode"> <div class="quarto-reader-toggle-btn"> <i class="bi"></i> </div> </a> </div> </div> </div> <div class="mt-2 flex-shrink-0 align-items-center"> <div class="sidebar-search"> <div id="quarto-search" class="" title="Search"></div> </div> </div> <div class="sidebar-menu-container"> <ul class="list-unstyled mt-1"> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./index.html" class="sidebar-item-text sidebar-link"> <span class="menu-text">Welcome</span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./preface-2e.html" class="sidebar-item-text sidebar-link"> <span class="menu-text">Preface to the second edition</span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./intro.html" class="sidebar-item-text sidebar-link"> <span class="menu-text">Introduction</span></a> </div> </li> <li class="sidebar-item sidebar-item-section"> <div class="sidebar-item-container"> <a href="./whole-game.html" class="sidebar-item-text sidebar-link"> <span class="menu-text">Whole game</span></a> <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" role="navigation" aria-expanded="true" aria-label="Toggle section"> <i class="bi bi-chevron-right ms-2"></i> </a> </div> <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 show"> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./data-visualize.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">1</span> <span class="chapter-title">Data visualization</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./workflow-basics.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">2</span> <span class="chapter-title">Workflow: basics</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./data-transform.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">3</span> <span class="chapter-title">Data transformation</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./workflow-style.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">4</span> <span class="chapter-title">Workflow: code style</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./data-tidy.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">5</span> <span class="chapter-title">Data tidying</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./workflow-scripts.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">6</span> <span class="chapter-title">Workflow: scripts and projects</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./data-import.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">7</span> <span class="chapter-title">Data import</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./workflow-help.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">8</span> <span class="chapter-title">Workflow: getting help</span></span></a> </div> </li> </ul> </li> <li class="sidebar-item sidebar-item-section"> <div class="sidebar-item-container"> <a href="./visualize.html" class="sidebar-item-text sidebar-link"> <span class="menu-text">Visualize</span></a> <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" role="navigation" aria-expanded="true" aria-label="Toggle section"> <i class="bi bi-chevron-right ms-2"></i> </a> </div> <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show"> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./layers.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">9</span> <span class="chapter-title">Layers</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./EDA.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">10</span> <span class="chapter-title">Exploratory data analysis</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./communication.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">11</span> <span class="chapter-title">Communication</span></span></a> </div> </li> </ul> </li> <li class="sidebar-item sidebar-item-section"> <div class="sidebar-item-container"> <a href="./transform.html" class="sidebar-item-text sidebar-link"> <span class="menu-text">Transform</span></a> <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" role="navigation" aria-expanded="true" aria-label="Toggle section"> <i class="bi bi-chevron-right ms-2"></i> </a> </div> <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth1 show"> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./logicals.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">12</span> <span class="chapter-title">Logical vectors</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./numbers.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">13</span> <span class="chapter-title">Numbers</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./strings.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">14</span> <span class="chapter-title">Strings</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./regexps.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">15</span> <span class="chapter-title">Regular expressions</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./factors.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">16</span> <span class="chapter-title">Factors</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./datetimes.html" class="sidebar-item-text sidebar-link active"> <span class="menu-text"><span class="chapter-number">17</span> <span class="chapter-title">Dates and times</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./missing-values.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">18</span> <span class="chapter-title">Missing values</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./joins.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">19</span> <span class="chapter-title">Joins</span></span></a> </div> </li> </ul> </li> <li class="sidebar-item sidebar-item-section"> <div class="sidebar-item-container"> <a href="./import.html" class="sidebar-item-text sidebar-link"> <span class="menu-text">Import</span></a> <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" role="navigation" aria-expanded="true" aria-label="Toggle section"> <i class="bi bi-chevron-right ms-2"></i> </a> </div> <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth1 show"> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./spreadsheets.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">20</span> <span class="chapter-title">Spreadsheets</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./databases.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">21</span> <span class="chapter-title">Databases</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./arrow.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">22</span> <span class="chapter-title">Arrow</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./rectangling.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">23</span> <span class="chapter-title">Hierarchical data</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./webscraping.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">24</span> <span class="chapter-title">Web scraping</span></span></a> </div> </li> </ul> </li> <li class="sidebar-item sidebar-item-section"> <div class="sidebar-item-container"> <a href="./program.html" class="sidebar-item-text sidebar-link"> <span class="menu-text">Program</span></a> <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" role="navigation" aria-expanded="true" aria-label="Toggle section"> <i class="bi bi-chevron-right ms-2"></i> </a> </div> <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth1 show"> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./functions.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">25</span> <span class="chapter-title">Functions</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./iteration.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">26</span> <span class="chapter-title">Iteration</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./base-R.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">27</span> <span class="chapter-title">A field guide to base R</span></span></a> </div> </li> </ul> </li> <li class="sidebar-item sidebar-item-section"> <div class="sidebar-item-container"> <a href="./communicate.html" class="sidebar-item-text sidebar-link"> <span class="menu-text">Communicate</span></a> <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" role="navigation" aria-expanded="true" aria-label="Toggle section"> <i class="bi bi-chevron-right ms-2"></i> </a> </div> <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 show"> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./quarto.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">28</span> <span class="chapter-title">Quarto</span></span></a> </div> </li> <li class="sidebar-item"> <div class="sidebar-item-container"> <a href="./quarto-formats.html" class="sidebar-item-text sidebar-link"> <span class="menu-text"><span class="chapter-number">29</span> <span class="chapter-title">Quarto formats</span></span></a> </div> </li> </ul> </li> </ul> </div> </nav><div id="quarto-sidebar-glass" class="quarto-sidebar-collapse-item" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item"></div> <!-- margin-sidebar --> <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> <nav id="TOC" role="doc-toc" class="toc-active"><h2 id="toc-title">Table of contents</h2> <ul> <li> <a href="#introduction" id="toc-introduction" class="nav-link active" data-scroll-target="#introduction"><span class="header-section-number">17.1</span> Introduction</a> <ul class="collapse"> <li><a href="#prerequisites" id="toc-prerequisites" class="nav-link" data-scroll-target="#prerequisites"><span class="header-section-number">17.1.1</span> Prerequisites</a></li> </ul> </li> <li> <a href="#sec-creating-datetimes" id="toc-sec-creating-datetimes" class="nav-link" data-scroll-target="#sec-creating-datetimes"><span class="header-section-number">17.2</span> Creating date/times</a> <ul class="collapse"> <li><a href="#during-import" id="toc-during-import" class="nav-link" data-scroll-target="#during-import"><span class="header-section-number">17.2.1</span> During import</a></li> <li><a href="#from-strings" id="toc-from-strings" class="nav-link" data-scroll-target="#from-strings"><span class="header-section-number">17.2.2</span> From strings</a></li> <li><a href="#from-individual-components" id="toc-from-individual-components" class="nav-link" data-scroll-target="#from-individual-components"><span class="header-section-number">17.2.3</span> From individual components</a></li> <li><a href="#from-other-types" id="toc-from-other-types" class="nav-link" data-scroll-target="#from-other-types"><span class="header-section-number">17.2.4</span> From other types</a></li> <li><a href="#exercises" id="toc-exercises" class="nav-link" data-scroll-target="#exercises"><span class="header-section-number">17.2.5</span> Exercises</a></li> </ul> </li> <li> <a href="#date-time-components" id="toc-date-time-components" class="nav-link" data-scroll-target="#date-time-components"><span class="header-section-number">17.3</span> Date-time components</a> <ul class="collapse"> <li><a href="#getting-components" id="toc-getting-components" class="nav-link" data-scroll-target="#getting-components"><span class="header-section-number">17.3.1</span> Getting components</a></li> <li><a href="#rounding" id="toc-rounding" class="nav-link" data-scroll-target="#rounding"><span class="header-section-number">17.3.2</span> Rounding</a></li> <li><a href="#modifying-components" id="toc-modifying-components" class="nav-link" data-scroll-target="#modifying-components"><span class="header-section-number">17.3.3</span> Modifying components</a></li> <li><a href="#exercises-1" id="toc-exercises-1" class="nav-link" data-scroll-target="#exercises-1"><span class="header-section-number">17.3.4</span> Exercises</a></li> </ul> </li> <li> <a href="#time-spans" id="toc-time-spans" class="nav-link" data-scroll-target="#time-spans"><span class="header-section-number">17.4</span> Time spans</a> <ul class="collapse"> <li><a href="#durations" id="toc-durations" class="nav-link" data-scroll-target="#durations"><span class="header-section-number">17.4.1</span> Durations</a></li> <li><a href="#periods" id="toc-periods" class="nav-link" data-scroll-target="#periods"><span class="header-section-number">17.4.2</span> Periods</a></li> <li><a href="#sec-intervals" id="toc-sec-intervals" class="nav-link" data-scroll-target="#sec-intervals"><span class="header-section-number">17.4.3</span> Intervals</a></li> <li><a href="#exercises-2" id="toc-exercises-2" class="nav-link" data-scroll-target="#exercises-2"><span class="header-section-number">17.4.4</span> Exercises</a></li> </ul> </li> <li><a href="#time-zones" id="toc-time-zones" class="nav-link" data-scroll-target="#time-zones"><span class="header-section-number">17.5</span> Time zones</a></li> <li><a href="#summary" id="toc-summary" class="nav-link" data-scroll-target="#summary"><span class="header-section-number">17.6</span> Summary</a></li> </ul><div class="toc-actions"><ul><li><a href="https://github.com/hadley/r4ds/edit/main/datetimes.qmd" class="toc-action"><i class="bi bi-github"></i>Edit this page</a></li><li><a href="https://github.com/hadley/r4ds/issues/new" class="toc-action"><i class="bi empty"></i>Report an issue</a></li></ul></div></nav> </div> <!-- main --> <main class="content" id="quarto-document-content"><header id="title-block-header" class="quarto-title-block default"><nav class="quarto-page-breadcrumbs quarto-title-breadcrumbs d-none d-lg-block" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="./transform.html">Transform</a></li><li class="breadcrumb-item"><a href="./datetimes.html"><span class="chapter-number">17</span> <span class="chapter-title">Dates and times</span></a></li></ol></nav><div class="quarto-title"> <h1 class="title"><span id="sec-dates-and-times" class="quarto-section-identifier"><span class="chapter-number">17</span> <span class="chapter-title">Dates and times</span></span></h1> </div> <div class="quarto-title-meta"> </div> </header><section id="introduction" class="level2" data-number="17.1"><h2 data-number="17.1" class="anchored" data-anchor-id="introduction"> <span class="header-section-number">17.1</span> Introduction</h2> <p>This chapter will show you how to work with dates and times in R. At first glance, dates and times seem simple. You use them all the time in your regular life, and they don’t seem to cause much confusion. However, the more you learn about dates and times, the more complicated they seem to get!</p> <p>To warm up think about how many days there are in a year, and how many hours there are in a day. You probably remembered that most years have 365 days, but leap years have 366. Do you know the full rule for determining if a year is a leap year<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>? The number of hours in a day is a little less obvious: most days have 24 hours, but in places that use daylight saving time (DST), one day each year has 23 hours and another has 25.</p> <p>Dates and times are hard because they have to reconcile two physical phenomena (the rotation of the Earth and its orbit around the sun) with a whole raft of geopolitical phenomena including months, time zones, and DST. This chapter won’t teach you every last detail about dates and times, but it will give you a solid grounding of practical skills that will help you with common data analysis challenges.</p> <p>We’ll begin by showing you how to create date-times from various inputs, and then once you’ve got a date-time, how you can extract components like year, month, and day. We’ll then dive into the tricky topic of working with time spans, which come in a variety of flavors depending on what you’re trying to do. We’ll conclude with a brief discussion of the additional challenges posed by time zones.</p> <section id="prerequisites" class="level3" data-number="17.1.1"><h3 data-number="17.1.1" class="anchored" data-anchor-id="prerequisites"> <span class="header-section-number">17.1.1</span> Prerequisites</h3> <p>This chapter will focus on the <strong>lubridate</strong> package, which makes it easier to work with dates and times in R. As of the latest tidyverse release, lubridate is part of core tidyverse. We will also need nycflights13 for practice data.</p> <div class="cell"> <div class="sourceCode" id="cb1"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="kw"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op">(</span><span class="va"><a href="https://tidyverse.tidyverse.org">tidyverse</a></span><span class="op">)</span></span> <span><span class="kw"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op">(</span><span class="va"><a href="https://github.com/hadley/nycflights13">nycflights13</a></span><span class="op">)</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> </section></section><section id="sec-creating-datetimes" class="level2" data-number="17.2"><h2 data-number="17.2" class="anchored" data-anchor-id="sec-creating-datetimes"> <span class="header-section-number">17.2</span> Creating date/times</h2> <p>There are three types of date/time data that refer to an instant in time:</p> <ul> <li><p>A <strong>date</strong>. Tibbles print this as <code><date></code>.</p></li> <li><p>A <strong>time</strong> within a day. Tibbles print this as <code><time></code>.</p></li> <li><p>A <strong>date-time</strong> is a date plus a time: it uniquely identifies an instant in time (typically to the nearest second). Tibbles print this as <code><dttm></code>. Base R calls these POSIXct, but that doesn’t exactly trip off the tongue.</p></li> </ul> <p>In this chapter we are going to focus on dates and date-times as R doesn’t have a native class for storing times. If you need one, you can use the <strong>hms</strong> package.</p> <p>You should always use the simplest possible data type that works for your needs. That means if you can use a date instead of a date-time, you should. Date-times are substantially more complicated because of the need to handle time zones, which we’ll come back to at the end of the chapter.</p> <p>To get the current date or date-time you can use <code><a href="https://lubridate.tidyverse.org/reference/now.html">today()</a></code> or <code><a href="https://lubridate.tidyverse.org/reference/now.html">now()</a></code>:</p> <div class="cell"> <div class="sourceCode" id="cb2"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/now.html">today</a></span><span class="op">(</span><span class="op">)</span></span> <span><span class="co">#> [1] "2025-02-22"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/now.html">now</a></span><span class="op">(</span><span class="op">)</span></span> <span><span class="co">#> [1] "2025-02-22 23:08:59 UTC"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Otherwise, the following sections describe the four ways you’re likely to create a date/time:</p> <ul> <li>While reading a file with readr.</li> <li>From a string.</li> <li>From individual date-time components.</li> <li>From an existing date/time object.</li> </ul> <section id="during-import" class="level3" data-number="17.2.1"><h3 data-number="17.2.1" class="anchored" data-anchor-id="during-import"> <span class="header-section-number">17.2.1</span> During import</h3> <p>If your CSV contains an ISO8601 date or date-time, you don’t need to do anything; readr will automatically recognize it:</p> <div class="cell"> <div class="sourceCode" id="cb3"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">csv</span> <span class="op"><-</span> <span class="st">"</span></span> <span><span class="st"> date,datetime</span></span> <span><span class="st"> 2022-01-02,2022-01-02 05:12</span></span> <span><span class="st">"</span></span> <span><span class="fu"><a href="https://readr.tidyverse.org/reference/read_delim.html">read_csv</a></span><span class="op">(</span><span class="va">csv</span><span class="op">)</span></span> <span><span class="co">#> # A tibble: 1 × 2</span></span> <span><span class="co">#> date datetime </span></span> <span><span class="co">#> <date> <dttm> </span></span> <span><span class="co">#> 1 2022-01-02 2022-01-02 05:12:00</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>If you haven’t heard of <strong>ISO8601</strong> before, it’s an international standard<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> for writing dates where the components of a date are organized from biggest to smallest separated by <code>-</code>. For example, in ISO8601 May 3 2022 is <code>2022-05-03</code>. ISO8601 dates can also include times, where hour, minute, and second are separated by <code>:</code>, and the date and time components are separated by either a <code>T</code> or a space. For example, you could write 4:26pm on May 3 2022 as either <code>2022-05-03 16:26</code> or <code>2022-05-03T16:26</code>.</p> <p>For other date-time formats, you’ll need to use <code>col_types</code> plus <code><a href="https://readr.tidyverse.org/reference/parse_datetime.html">col_date()</a></code> or <code><a href="https://readr.tidyverse.org/reference/parse_datetime.html">col_datetime()</a></code> along with a date-time format. The date-time format used by readr is a standard used across many programming languages, describing a date component with a <code>%</code> followed by a single character. For example, <code>%Y-%m-%d</code> specifies a date that’s a year, <code>-</code>, month (as number) <code>-</code>, day. Table <a href="#tbl-date-formats" class="quarto-xref">Table <span>17.1</span></a> lists all the options.</p> <div id="tbl-date-formats" class="quarto-float quarto-figure quarto-figure-center anchored"> <figure class="quarto-float quarto-float-tbl figure"><figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-date-formats-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca"> Table 17.1: All date formats understood by readr </figcaption><div aria-describedby="tbl-date-formats-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca"> <table class="caption-top table"> <thead><tr class="header"> <th>Type</th> <th>Code</th> <th>Meaning</th> <th>Example</th> </tr></thead> <tbody> <tr class="odd"> <td>Year</td> <td><code>%Y</code></td> <td>4 digit year</td> <td>2021</td> </tr> <tr class="even"> <td></td> <td><code>%y</code></td> <td>2 digit year</td> <td>21</td> </tr> <tr class="odd"> <td>Month</td> <td><code>%m</code></td> <td>Number</td> <td>2</td> </tr> <tr class="even"> <td></td> <td><code>%b</code></td> <td>Abbreviated name</td> <td>Feb</td> </tr> <tr class="odd"> <td></td> <td><code>%B</code></td> <td>Full name</td> <td>February</td> </tr> <tr class="even"> <td>Day</td> <td><code>%d</code></td> <td>One or two digits</td> <td>2</td> </tr> <tr class="odd"> <td></td> <td><code>%e</code></td> <td>Two digits</td> <td>02</td> </tr> <tr class="even"> <td>Time</td> <td><code>%H</code></td> <td>24-hour hour</td> <td>13</td> </tr> <tr class="odd"> <td></td> <td><code>%I</code></td> <td>12-hour hour</td> <td>1</td> </tr> <tr class="even"> <td></td> <td><code>%p</code></td> <td>AM/PM</td> <td>pm</td> </tr> <tr class="odd"> <td></td> <td><code>%M</code></td> <td>Minutes</td> <td>35</td> </tr> <tr class="even"> <td></td> <td><code>%S</code></td> <td>Seconds</td> <td>45</td> </tr> <tr class="odd"> <td></td> <td><code>%OS</code></td> <td>Seconds with decimal component</td> <td>45.35</td> </tr> <tr class="even"> <td></td> <td><code>%Z</code></td> <td>Time zone name</td> <td>America/Chicago</td> </tr> <tr class="odd"> <td></td> <td><code>%z</code></td> <td>Offset from UTC</td> <td>+0800</td> </tr> <tr class="even"> <td>Other</td> <td><code>%.</code></td> <td>Skip one non-digit</td> <td>:</td> </tr> <tr class="odd"> <td></td> <td><code>%*</code></td> <td>Skip any number of non-digits</td> <td></td> </tr> </tbody> </table> </div> </figure> </div> <p>And this code shows a few options applied to a very ambiguous date:</p> <div class="cell" data-messages="false"> <div class="sourceCode" id="cb4"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">csv</span> <span class="op"><-</span> <span class="st">"</span></span> <span><span class="st"> date</span></span> <span><span class="st"> 01/02/15</span></span> <span><span class="st">"</span></span> <span></span> <span><span class="fu"><a href="https://readr.tidyverse.org/reference/read_delim.html">read_csv</a></span><span class="op">(</span><span class="va">csv</span>, col_types <span class="op">=</span> <span class="fu"><a href="https://readr.tidyverse.org/reference/cols.html">cols</a></span><span class="op">(</span>date <span class="op">=</span> <span class="fu"><a href="https://readr.tidyverse.org/reference/parse_datetime.html">col_date</a></span><span class="op">(</span><span class="st">"%m/%d/%y"</span><span class="op">)</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> # A tibble: 1 × 1</span></span> <span><span class="co">#> date </span></span> <span><span class="co">#> <date> </span></span> <span><span class="co">#> 1 2015-01-02</span></span> <span></span> <span><span class="fu"><a href="https://readr.tidyverse.org/reference/read_delim.html">read_csv</a></span><span class="op">(</span><span class="va">csv</span>, col_types <span class="op">=</span> <span class="fu"><a href="https://readr.tidyverse.org/reference/cols.html">cols</a></span><span class="op">(</span>date <span class="op">=</span> <span class="fu"><a href="https://readr.tidyverse.org/reference/parse_datetime.html">col_date</a></span><span class="op">(</span><span class="st">"%d/%m/%y"</span><span class="op">)</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> # A tibble: 1 × 1</span></span> <span><span class="co">#> date </span></span> <span><span class="co">#> <date> </span></span> <span><span class="co">#> 1 2015-02-01</span></span> <span></span> <span><span class="fu"><a href="https://readr.tidyverse.org/reference/read_delim.html">read_csv</a></span><span class="op">(</span><span class="va">csv</span>, col_types <span class="op">=</span> <span class="fu"><a href="https://readr.tidyverse.org/reference/cols.html">cols</a></span><span class="op">(</span>date <span class="op">=</span> <span class="fu"><a href="https://readr.tidyverse.org/reference/parse_datetime.html">col_date</a></span><span class="op">(</span><span class="st">"%y/%m/%d"</span><span class="op">)</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> # A tibble: 1 × 1</span></span> <span><span class="co">#> date </span></span> <span><span class="co">#> <date> </span></span> <span><span class="co">#> 1 2001-02-15</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Note that no matter how you specify the date format, it’s always displayed the same way once you get it into R.</p> <p>If you’re using <code>%b</code> or <code>%B</code> and working with non-English dates, you’ll also need to provide a <code><a href="https://readr.tidyverse.org/reference/locale.html">locale()</a></code>. See the list of built-in languages in <code><a href="https://readr.tidyverse.org/reference/date_names.html">date_names_langs()</a></code>, or create your own with <code><a href="https://readr.tidyverse.org/reference/date_names.html">date_names()</a></code>,</p> </section><section id="from-strings" class="level3" data-number="17.2.2"><h3 data-number="17.2.2" class="anchored" data-anchor-id="from-strings"> <span class="header-section-number">17.2.2</span> From strings</h3> <p>The date-time specification language is powerful, but requires careful analysis of the date format. An alternative approach is to use lubridate’s helpers which attempt to automatically determine the format once you specify the order of the component. To use them, identify the order in which year, month, and day appear in your dates, then arrange “y”, “m”, and “d” in the same order. That gives you the name of the lubridate function that will parse your date. For example:</p> <div class="cell"> <div class="sourceCode" id="cb5"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="st">"2017-01-31"</span><span class="op">)</span></span> <span><span class="co">#> [1] "2017-01-31"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">mdy</a></span><span class="op">(</span><span class="st">"January 31st, 2017"</span><span class="op">)</span></span> <span><span class="co">#> [1] "2017-01-31"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">dmy</a></span><span class="op">(</span><span class="st">"31-Jan-2017"</span><span class="op">)</span></span> <span><span class="co">#> [1] "2017-01-31"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p><code><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd()</a></code> and friends create dates. To create a date-time, add an underscore and one or more of “h”, “m”, and “s” to the name of the parsing function:</p> <div class="cell"> <div class="sourceCode" id="cb6"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd_hms.html">ymd_hms</a></span><span class="op">(</span><span class="st">"2017-01-31 20:11:59"</span><span class="op">)</span></span> <span><span class="co">#> [1] "2017-01-31 20:11:59 UTC"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd_hms.html">mdy_hm</a></span><span class="op">(</span><span class="st">"01/31/2017 08:01"</span><span class="op">)</span></span> <span><span class="co">#> [1] "2017-01-31 08:01:00 UTC"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>You can also force the creation of a date-time from a date by supplying a timezone:</p> <div class="cell"> <div class="sourceCode" id="cb7"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="st">"2017-01-31"</span>, tz <span class="op">=</span> <span class="st">"UTC"</span><span class="op">)</span></span> <span><span class="co">#> [1] "2017-01-31 UTC"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Here I use the UTC<a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a> timezone which you might also know as GMT, or Greenwich Mean Time, the time at 0° longitude<a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a> . It doesn’t use daylight saving time, making it a bit easier to compute with .</p> </section><section id="from-individual-components" class="level3" data-number="17.2.3"><h3 data-number="17.2.3" class="anchored" data-anchor-id="from-individual-components"> <span class="header-section-number">17.2.3</span> From individual components</h3> <p>Instead of a single string, sometimes you’ll have the individual components of the date-time spread across multiple columns. This is what we have in the <code>flights</code> data:</p> <div class="cell"> <div class="sourceCode" id="cb8"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/select.html">select</a></span><span class="op">(</span><span class="va">year</span>, <span class="va">month</span>, <span class="va">day</span>, <span class="va">hour</span>, <span class="va">minute</span><span class="op">)</span></span> <span><span class="co">#> # A tibble: 336,776 × 5</span></span> <span><span class="co">#> year month day hour minute</span></span> <span><span class="co">#> <int> <int> <int> <dbl> <dbl></span></span> <span><span class="co">#> 1 2013 1 1 5 15</span></span> <span><span class="co">#> 2 2013 1 1 5 29</span></span> <span><span class="co">#> 3 2013 1 1 5 40</span></span> <span><span class="co">#> 4 2013 1 1 5 45</span></span> <span><span class="co">#> 5 2013 1 1 6 0</span></span> <span><span class="co">#> 6 2013 1 1 5 58</span></span> <span><span class="co">#> # ℹ 336,770 more rows</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>To create a date/time from this sort of input, use <code><a href="https://lubridate.tidyverse.org/reference/make_datetime.html">make_date()</a></code> for dates, or <code><a href="https://lubridate.tidyverse.org/reference/make_datetime.html">make_datetime()</a></code> for date-times:</p> <div class="cell"> <div class="sourceCode" id="cb9"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/select.html">select</a></span><span class="op">(</span><span class="va">year</span>, <span class="va">month</span>, <span class="va">day</span>, <span class="va">hour</span>, <span class="va">minute</span><span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/mutate.html">mutate</a></span><span class="op">(</span>departure <span class="op">=</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/make_datetime.html">make_datetime</a></span><span class="op">(</span><span class="va">year</span>, <span class="va">month</span>, <span class="va">day</span>, <span class="va">hour</span>, <span class="va">minute</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> # A tibble: 336,776 × 6</span></span> <span><span class="co">#> year month day hour minute departure </span></span> <span><span class="co">#> <int> <int> <int> <dbl> <dbl> <dttm> </span></span> <span><span class="co">#> 1 2013 1 1 5 15 2013-01-01 05:15:00</span></span> <span><span class="co">#> 2 2013 1 1 5 29 2013-01-01 05:29:00</span></span> <span><span class="co">#> 3 2013 1 1 5 40 2013-01-01 05:40:00</span></span> <span><span class="co">#> 4 2013 1 1 5 45 2013-01-01 05:45:00</span></span> <span><span class="co">#> 5 2013 1 1 6 0 2013-01-01 06:00:00</span></span> <span><span class="co">#> 6 2013 1 1 5 58 2013-01-01 05:58:00</span></span> <span><span class="co">#> # ℹ 336,770 more rows</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Let’s do the same thing for each of the four time columns in <code>flights</code>. The times are represented in a slightly odd format, so we use modulus arithmetic to pull out the hour and minute components. Once we’ve created the date-time variables, we focus in on the variables we’ll explore in the rest of the chapter.</p> <div class="cell"> <div class="sourceCode" id="cb10"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">make_datetime_100</span> <span class="op"><-</span> <span class="kw">function</span><span class="op">(</span><span class="va">year</span>, <span class="va">month</span>, <span class="va">day</span>, <span class="va">time</span><span class="op">)</span> <span class="op">{</span></span> <span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/make_datetime.html">make_datetime</a></span><span class="op">(</span><span class="va">year</span>, <span class="va">month</span>, <span class="va">day</span>, <span class="va">time</span> <span class="op"><a href="https://rdrr.io/r/base/Arithmetic.html">%/%</a></span> <span class="fl">100</span>, <span class="va">time</span> <span class="op"><a href="https://rdrr.io/r/base/Arithmetic.html">%%</a></span> <span class="fl">100</span><span class="op">)</span></span> <span><span class="op">}</span></span> <span></span> <span><span class="va">flights_dt</span> <span class="op"><-</span> <span class="va">flights</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/filter.html">filter</a></span><span class="op">(</span><span class="op">!</span><span class="fu"><a href="https://rdrr.io/r/base/NA.html">is.na</a></span><span class="op">(</span><span class="va">dep_time</span><span class="op">)</span>, <span class="op">!</span><span class="fu"><a href="https://rdrr.io/r/base/NA.html">is.na</a></span><span class="op">(</span><span class="va">arr_time</span><span class="op">)</span><span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/mutate.html">mutate</a></span><span class="op">(</span></span> <span> dep_time <span class="op">=</span> <span class="fu">make_datetime_100</span><span class="op">(</span><span class="va">year</span>, <span class="va">month</span>, <span class="va">day</span>, <span class="va">dep_time</span><span class="op">)</span>,</span> <span> arr_time <span class="op">=</span> <span class="fu">make_datetime_100</span><span class="op">(</span><span class="va">year</span>, <span class="va">month</span>, <span class="va">day</span>, <span class="va">arr_time</span><span class="op">)</span>,</span> <span> sched_dep_time <span class="op">=</span> <span class="fu">make_datetime_100</span><span class="op">(</span><span class="va">year</span>, <span class="va">month</span>, <span class="va">day</span>, <span class="va">sched_dep_time</span><span class="op">)</span>,</span> <span> sched_arr_time <span class="op">=</span> <span class="fu">make_datetime_100</span><span class="op">(</span><span class="va">year</span>, <span class="va">month</span>, <span class="va">day</span>, <span class="va">sched_arr_time</span><span class="op">)</span></span> <span> <span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/select.html">select</a></span><span class="op">(</span><span class="va">origin</span>, <span class="va">dest</span>, <span class="fu"><a href="https://tidyselect.r-lib.org/reference/starts_with.html">ends_with</a></span><span class="op">(</span><span class="st">"delay"</span><span class="op">)</span>, <span class="fu"><a href="https://tidyselect.r-lib.org/reference/starts_with.html">ends_with</a></span><span class="op">(</span><span class="st">"time"</span><span class="op">)</span><span class="op">)</span></span> <span></span> <span><span class="va">flights_dt</span></span> <span><span class="co">#> # A tibble: 328,063 × 9</span></span> <span><span class="co">#> origin dest dep_delay arr_delay dep_time sched_dep_time </span></span> <span><span class="co">#> <chr> <chr> <dbl> <dbl> <dttm> <dttm> </span></span> <span><span class="co">#> 1 EWR IAH 2 11 2013-01-01 05:17:00 2013-01-01 05:15:00</span></span> <span><span class="co">#> 2 LGA IAH 4 20 2013-01-01 05:33:00 2013-01-01 05:29:00</span></span> <span><span class="co">#> 3 JFK MIA 2 33 2013-01-01 05:42:00 2013-01-01 05:40:00</span></span> <span><span class="co">#> 4 JFK BQN -1 -18 2013-01-01 05:44:00 2013-01-01 05:45:00</span></span> <span><span class="co">#> 5 LGA ATL -6 -25 2013-01-01 05:54:00 2013-01-01 06:00:00</span></span> <span><span class="co">#> 6 EWR ORD -4 12 2013-01-01 05:54:00 2013-01-01 05:58:00</span></span> <span><span class="co">#> # ℹ 328,057 more rows</span></span> <span><span class="co">#> # ℹ 3 more variables: arr_time <dttm>, sched_arr_time <dttm>, …</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>With this data, we can visualize the distribution of departure times across the year:</p> <div class="cell"> <div class="sourceCode" id="cb11"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights_dt</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/ggplot.html">ggplot</a></span><span class="op">(</span><span class="fu"><a href="https://ggplot2.tidyverse.org/reference/aes.html">aes</a></span><span class="op">(</span>x <span class="op">=</span> <span class="va">dep_time</span><span class="op">)</span><span class="op">)</span> <span class="op">+</span> </span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/geom_histogram.html">geom_freqpoly</a></span><span class="op">(</span>binwidth <span class="op">=</span> <span class="fl">86400</span><span class="op">)</span> <span class="co"># 86400 seconds = 1 day</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> <div class="cell-output-display"> <div> <figure class="figure"><p><img src="datetimes_files/figure-html/unnamed-chunk-12-1.png" class="img-fluid figure-img" alt="A frequency polyon with departure time (Jan-Dec 2013) on the x-axis and number of flights on the y-axis (0-1000). The frequency polygon is binned by day so you see a time series of flights by day. The pattern is dominated by a weekly pattern; there are fewer flights on weekends. The are few days that stand out as having a surprisingly few flights in early February, early July, late November, and late December." width="576"></p> </figure> </div> </div> </div> <p>Or within a single day:</p> <div class="cell"> <div class="sourceCode" id="cb12"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights_dt</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/filter.html">filter</a></span><span class="op">(</span><span class="va">dep_time</span> <span class="op"><</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="fl">20130102</span><span class="op">)</span><span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/ggplot.html">ggplot</a></span><span class="op">(</span><span class="fu"><a href="https://ggplot2.tidyverse.org/reference/aes.html">aes</a></span><span class="op">(</span>x <span class="op">=</span> <span class="va">dep_time</span><span class="op">)</span><span class="op">)</span> <span class="op">+</span> </span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/geom_histogram.html">geom_freqpoly</a></span><span class="op">(</span>binwidth <span class="op">=</span> <span class="fl">600</span><span class="op">)</span> <span class="co"># 600 s = 10 minutes</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> <div class="cell-output-display"> <div> <figure class="figure"><p><img src="datetimes_files/figure-html/unnamed-chunk-13-1.png" class="img-fluid figure-img" alt="A frequency polygon with departure time (6am - midnight Jan 1) on the x-axis, number of flights on the y-axis (0-17), binned into 10 minute increments. It's hard to see much pattern because of high variability, but most bins have 8-12 flights, and there are markedly fewer flights before 6am and after 8pm." width="576"></p> </figure> </div> </div> </div> <p>Note that when you use date-times in a numeric context (like in a histogram), 1 means 1 second, so a binwidth of 86400 means one day. For dates, 1 means 1 day.</p> </section><section id="from-other-types" class="level3" data-number="17.2.4"><h3 data-number="17.2.4" class="anchored" data-anchor-id="from-other-types"> <span class="header-section-number">17.2.4</span> From other types</h3> <p>You may want to switch between a date-time and a date. That’s the job of <code><a href="https://lubridate.tidyverse.org/reference/as_date.html">as_datetime()</a></code> and <code><a href="https://lubridate.tidyverse.org/reference/as_date.html">as_date()</a></code>:</p> <div class="cell"> <div class="sourceCode" id="cb13"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/as_date.html">as_datetime</a></span><span class="op">(</span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/now.html">today</a></span><span class="op">(</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> [1] "2025-02-22 UTC"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/as_date.html">as_date</a></span><span class="op">(</span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/now.html">now</a></span><span class="op">(</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> [1] "2025-02-22"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Sometimes you’ll get date/times as numeric offsets from the “Unix Epoch”, 1970-01-01. If the offset is in seconds, use <code><a href="https://lubridate.tidyverse.org/reference/as_date.html">as_datetime()</a></code>; if it’s in days, use <code><a href="https://lubridate.tidyverse.org/reference/as_date.html">as_date()</a></code>.</p> <div class="cell"> <div class="sourceCode" id="cb14"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/as_date.html">as_datetime</a></span><span class="op">(</span><span class="fl">60</span> <span class="op">*</span> <span class="fl">60</span> <span class="op">*</span> <span class="fl">10</span><span class="op">)</span></span> <span><span class="co">#> [1] "1970-01-01 10:00:00 UTC"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/as_date.html">as_date</a></span><span class="op">(</span><span class="fl">365</span> <span class="op">*</span> <span class="fl">10</span> <span class="op">+</span> <span class="fl">2</span><span class="op">)</span></span> <span><span class="co">#> [1] "1980-01-01"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> </section><section id="exercises" class="level3" data-number="17.2.5"><h3 data-number="17.2.5" class="anchored" data-anchor-id="exercises"> <span class="header-section-number">17.2.5</span> Exercises</h3> <ol type="1"> <li> <p>What happens if you parse a string that contains invalid dates?</p> <div class="cell"> <div class="sourceCode" id="cb15"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="fu"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op">(</span><span class="st">"2010-10-10"</span>, <span class="st">"bananas"</span><span class="op">)</span><span class="op">)</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> </li> <li><p>What does the <code>tzone</code> argument to <code><a href="https://lubridate.tidyverse.org/reference/now.html">today()</a></code> do? Why is it important?</p></li> <li> <p>For each of the following date-times, show how you’d parse it using a readr column specification and a lubridate function.</p> <div class="cell"> <div class="sourceCode" id="cb16"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">d1</span> <span class="op"><-</span> <span class="st">"January 1, 2010"</span></span> <span><span class="va">d2</span> <span class="op"><-</span> <span class="st">"2015-Mar-07"</span></span> <span><span class="va">d3</span> <span class="op"><-</span> <span class="st">"06-Jun-2017"</span></span> <span><span class="va">d4</span> <span class="op"><-</span> <span class="fu"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op">(</span><span class="st">"August 19 (2015)"</span>, <span class="st">"July 1 (2015)"</span><span class="op">)</span></span> <span><span class="va">d5</span> <span class="op"><-</span> <span class="st">"12/30/14"</span> <span class="co"># Dec 30, 2014</span></span> <span><span class="va">t1</span> <span class="op"><-</span> <span class="st">"1705"</span></span> <span><span class="va">t2</span> <span class="op"><-</span> <span class="st">"11:15:10.12 PM"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> </li> </ol></section></section><section id="date-time-components" class="level2" data-number="17.3"><h2 data-number="17.3" class="anchored" data-anchor-id="date-time-components"> <span class="header-section-number">17.3</span> Date-time components</h2> <p>Now that you know how to get date-time data into R’s date-time data structures, let’s explore what you can do with them. This section will focus on the accessor functions that let you get and set individual components. The next section will look at how arithmetic works with date-times.</p> <section id="getting-components" class="level3" data-number="17.3.1"><h3 data-number="17.3.1" class="anchored" data-anchor-id="getting-components"> <span class="header-section-number">17.3.1</span> Getting components</h3> <p>You can pull out individual parts of the date with the accessor functions <code><a href="https://lubridate.tidyverse.org/reference/year.html">year()</a></code>, <code><a href="https://lubridate.tidyverse.org/reference/month.html">month()</a></code>, <code><a href="https://lubridate.tidyverse.org/reference/day.html">mday()</a></code> (day of the month), <code><a href="https://lubridate.tidyverse.org/reference/day.html">yday()</a></code> (day of the year), <code><a href="https://lubridate.tidyverse.org/reference/day.html">wday()</a></code> (day of the week), <code><a href="https://lubridate.tidyverse.org/reference/hour.html">hour()</a></code>, <code><a href="https://lubridate.tidyverse.org/reference/minute.html">minute()</a></code>, and <code><a href="https://lubridate.tidyverse.org/reference/second.html">second()</a></code>. These are effectively the opposites of <code><a href="https://lubridate.tidyverse.org/reference/make_datetime.html">make_datetime()</a></code>.</p> <div class="cell"> <div class="sourceCode" id="cb17"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">datetime</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd_hms.html">ymd_hms</a></span><span class="op">(</span><span class="st">"2026-07-08 12:34:56"</span><span class="op">)</span></span> <span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/year.html">year</a></span><span class="op">(</span><span class="va">datetime</span><span class="op">)</span></span> <span><span class="co">#> [1] 2026</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/month.html">month</a></span><span class="op">(</span><span class="va">datetime</span><span class="op">)</span></span> <span><span class="co">#> [1] 7</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/day.html">mday</a></span><span class="op">(</span><span class="va">datetime</span><span class="op">)</span></span> <span><span class="co">#> [1] 8</span></span> <span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/day.html">yday</a></span><span class="op">(</span><span class="va">datetime</span><span class="op">)</span></span> <span><span class="co">#> [1] 189</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/day.html">wday</a></span><span class="op">(</span><span class="va">datetime</span><span class="op">)</span></span> <span><span class="co">#> [1] 4</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>For <code><a href="https://lubridate.tidyverse.org/reference/month.html">month()</a></code> and <code><a href="https://lubridate.tidyverse.org/reference/day.html">wday()</a></code> you can set <code>label = TRUE</code> to return the abbreviated name of the month or day of the week. Set <code>abbr = FALSE</code> to return the full name.</p> <div class="cell"> <div class="sourceCode" id="cb18"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/month.html">month</a></span><span class="op">(</span><span class="va">datetime</span>, label <span class="op">=</span> <span class="cn">TRUE</span><span class="op">)</span></span> <span><span class="co">#> [1] Jul</span></span> <span><span class="co">#> 12 Levels: Jan < Feb < Mar < Apr < May < Jun < Jul < Aug < Sep < ... < Dec</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/day.html">wday</a></span><span class="op">(</span><span class="va">datetime</span>, label <span class="op">=</span> <span class="cn">TRUE</span>, abbr <span class="op">=</span> <span class="cn">FALSE</span><span class="op">)</span></span> <span><span class="co">#> [1] Wednesday</span></span> <span><span class="co">#> 7 Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < ... < Saturday</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>We can use <code><a href="https://lubridate.tidyverse.org/reference/day.html">wday()</a></code> to see that more flights depart during the week than on the weekend:</p> <div class="cell"> <div class="sourceCode" id="cb19"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights_dt</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/mutate.html">mutate</a></span><span class="op">(</span>wday <span class="op">=</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/day.html">wday</a></span><span class="op">(</span><span class="va">dep_time</span>, label <span class="op">=</span> <span class="cn">TRUE</span><span class="op">)</span><span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/ggplot.html">ggplot</a></span><span class="op">(</span><span class="fu"><a href="https://ggplot2.tidyverse.org/reference/aes.html">aes</a></span><span class="op">(</span>x <span class="op">=</span> <span class="va">wday</span><span class="op">)</span><span class="op">)</span> <span class="op">+</span></span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/geom_bar.html">geom_bar</a></span><span class="op">(</span><span class="op">)</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> <div class="cell-output-display"> <div> <figure class="figure"><p><img src="datetimes_files/figure-html/unnamed-chunk-20-1.png" class="img-fluid figure-img" alt="A bar chart with days of the week on the x-axis and number of flights on the y-axis. Monday-Friday have roughly the same number of flights, ~48,0000, decreasingly slightly over the course of the week. Sunday is a little lower (~45,000), and Saturday is much lower (~38,000)." width="576"></p> </figure> </div> </div> </div> <p>We can also look at the average departure delay by minute within the hour. There’s an interesting pattern: flights leaving in minutes 20-30 and 50-60 have much lower delays than the rest of the hour!</p> <div class="cell"> <div class="sourceCode" id="cb20"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights_dt</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/mutate.html">mutate</a></span><span class="op">(</span>minute <span class="op">=</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/minute.html">minute</a></span><span class="op">(</span><span class="va">dep_time</span><span class="op">)</span><span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/group_by.html">group_by</a></span><span class="op">(</span><span class="va">minute</span><span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/summarise.html">summarize</a></span><span class="op">(</span></span> <span> avg_delay <span class="op">=</span> <span class="fu"><a href="https://rdrr.io/r/base/mean.html">mean</a></span><span class="op">(</span><span class="va">dep_delay</span>, na.rm <span class="op">=</span> <span class="cn">TRUE</span><span class="op">)</span>,</span> <span> n <span class="op">=</span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/context.html">n</a></span><span class="op">(</span><span class="op">)</span></span> <span> <span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/ggplot.html">ggplot</a></span><span class="op">(</span><span class="fu"><a href="https://ggplot2.tidyverse.org/reference/aes.html">aes</a></span><span class="op">(</span>x <span class="op">=</span> <span class="va">minute</span>, y <span class="op">=</span> <span class="va">avg_delay</span><span class="op">)</span><span class="op">)</span> <span class="op">+</span></span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/geom_path.html">geom_line</a></span><span class="op">(</span><span class="op">)</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> <div class="cell-output-display"> <div> <figure class="figure"><p><img src="datetimes_files/figure-html/unnamed-chunk-21-1.png" class="img-fluid figure-img" alt="A line chart with minute of actual departure (0-60) on the x-axis and average delay (4-20) on the y-axis. Average delay starts at (0, 12), steadily increases to (18, 20), then sharply drops, hitting at minimum at ~23 minute past the hour and 9 minutes of delay. It then increases again to (17, 35), and sharply decreases to (55, 4). It finishes off with an increase to (60, 9)." width="576"></p> </figure> </div> </div> </div> <p>Interestingly, if we look at the <em>scheduled</em> departure time we don’t see such a strong pattern:</p> <div class="cell"> <div class="sourceCode" id="cb21"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">sched_dep</span> <span class="op"><-</span> <span class="va">flights_dt</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/mutate.html">mutate</a></span><span class="op">(</span>minute <span class="op">=</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/minute.html">minute</a></span><span class="op">(</span><span class="va">sched_dep_time</span><span class="op">)</span><span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/group_by.html">group_by</a></span><span class="op">(</span><span class="va">minute</span><span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/summarise.html">summarize</a></span><span class="op">(</span></span> <span> avg_delay <span class="op">=</span> <span class="fu"><a href="https://rdrr.io/r/base/mean.html">mean</a></span><span class="op">(</span><span class="va">arr_delay</span>, na.rm <span class="op">=</span> <span class="cn">TRUE</span><span class="op">)</span>,</span> <span> n <span class="op">=</span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/context.html">n</a></span><span class="op">(</span><span class="op">)</span></span> <span> <span class="op">)</span></span> <span></span> <span><span class="fu"><a href="https://ggplot2.tidyverse.org/reference/ggplot.html">ggplot</a></span><span class="op">(</span><span class="va">sched_dep</span>, <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/aes.html">aes</a></span><span class="op">(</span>x <span class="op">=</span> <span class="va">minute</span>, y <span class="op">=</span> <span class="va">avg_delay</span><span class="op">)</span><span class="op">)</span> <span class="op">+</span></span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/geom_path.html">geom_line</a></span><span class="op">(</span><span class="op">)</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> <div class="cell-output-display"> <div> <figure class="figure"><p><img src="datetimes_files/figure-html/unnamed-chunk-22-1.png" class="img-fluid figure-img" alt="A line chart with minute of scheduled departure (0-60) on the x-axis and average delay (4-16). There is relatively little pattern, just a small suggestion that the average delay decreases from maybe 10 minutes to 8 minutes over the course of the hour." width="576"></p> </figure> </div> </div> </div> <p>So why do we see that pattern with the actual departure times? Well, like much data collected by humans, there’s a strong bias towards flights leaving at “nice” departure times, as <a href="#fig-human-rounding" class="quarto-xref">Figure <span>17.1</span></a> shows. Always be alert for this sort of pattern whenever you work with data that involves human judgement!</p> <div class="cell"> <div class="cell-output-display"> <div id="fig-human-rounding" class="quarto-float quarto-figure quarto-figure-center anchored" alt="A line plot with departure minute (0-60) on the x-axis and number of flights (0-60000) on the y-axis. Most flights are scheduled to depart on either the hour (~60,000) or the half hour (~35,000). Otherwise, all most all flights are scheduled to depart on multiples of five, with a few extra at 15, 45, and 55 minutes. "> <figure class="quarto-float quarto-float-fig figure"><div aria-describedby="fig-human-rounding-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca"> <img src="datetimes_files/figure-html/fig-human-rounding-1.png" class="img-fluid figure-img" alt="A line plot with departure minute (0-60) on the x-axis and number of flights (0-60000) on the y-axis. Most flights are scheduled to depart on either the hour (~60,000) or the half hour (~35,000). Otherwise, all most all flights are scheduled to depart on multiples of five, with a few extra at 15, 45, and 55 minutes. " width="576"> </div> <figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-human-rounding-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca"> Figure 17.1: A frequency polygon showing the number of flights scheduled to depart each hour. You can see a strong preference for round numbers like 0 and 30 and generally for numbers that are a multiple of five. </figcaption></figure> </div> </div> </div> </section><section id="rounding" class="level3" data-number="17.3.2"><h3 data-number="17.3.2" class="anchored" data-anchor-id="rounding"> <span class="header-section-number">17.3.2</span> Rounding</h3> <p>An alternative approach to plotting individual components is to round the date to a nearby unit of time, with <code><a href="https://lubridate.tidyverse.org/reference/round_date.html">floor_date()</a></code>, <code><a href="https://lubridate.tidyverse.org/reference/round_date.html">round_date()</a></code>, and <code><a href="https://lubridate.tidyverse.org/reference/round_date.html">ceiling_date()</a></code>. Each function takes a vector of dates to adjust and then the name of the unit to round down (floor), round up (ceiling), or round to. This, for example, allows us to plot the number of flights per week:</p> <div class="cell"> <div class="sourceCode" id="cb22"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights_dt</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/count.html">count</a></span><span class="op">(</span>week <span class="op">=</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/round_date.html">floor_date</a></span><span class="op">(</span><span class="va">dep_time</span>, <span class="st">"week"</span><span class="op">)</span><span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/ggplot.html">ggplot</a></span><span class="op">(</span><span class="fu"><a href="https://ggplot2.tidyverse.org/reference/aes.html">aes</a></span><span class="op">(</span>x <span class="op">=</span> <span class="va">week</span>, y <span class="op">=</span> <span class="va">n</span><span class="op">)</span><span class="op">)</span> <span class="op">+</span></span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/geom_path.html">geom_line</a></span><span class="op">(</span><span class="op">)</span> <span class="op">+</span> </span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/geom_point.html">geom_point</a></span><span class="op">(</span><span class="op">)</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> <div class="cell-output-display"> <div> <figure class="figure"><p><img src="datetimes_files/figure-html/unnamed-chunk-24-1.png" class="img-fluid figure-img" alt="A line plot with week (Jan-Dec 2013) on the x-axis and number of flights (2,000-7,000) on the y-axis. The pattern is fairly flat from February to November with around 7,000 flights per week. There are far fewer flights on the first (approximately 4,500 flights) and last weeks of the year (approximately 2,500 flights)." width="576"></p> </figure> </div> </div> </div> <p>You can use rounding to show the distribution of flights across the course of a day by computing the difference between <code>dep_time</code> and the earliest instant of that day:</p> <div class="cell"> <div class="sourceCode" id="cb23"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights_dt</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/mutate.html">mutate</a></span><span class="op">(</span>dep_hour <span class="op">=</span> <span class="va">dep_time</span> <span class="op">-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/round_date.html">floor_date</a></span><span class="op">(</span><span class="va">dep_time</span>, <span class="st">"day"</span><span class="op">)</span><span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/ggplot.html">ggplot</a></span><span class="op">(</span><span class="fu"><a href="https://ggplot2.tidyverse.org/reference/aes.html">aes</a></span><span class="op">(</span>x <span class="op">=</span> <span class="va">dep_hour</span><span class="op">)</span><span class="op">)</span> <span class="op">+</span></span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/geom_histogram.html">geom_freqpoly</a></span><span class="op">(</span>binwidth <span class="op">=</span> <span class="fl">60</span> <span class="op">*</span> <span class="fl">30</span><span class="op">)</span></span> <span><span class="co">#> Don't know how to automatically pick scale for object of type <difftime>.</span></span> <span><span class="co">#> Defaulting to continuous.</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> <div class="cell-output-display"> <div> <figure class="figure"><p><img src="datetimes_files/figure-html/unnamed-chunk-25-1.png" class="img-fluid figure-img" alt="A line plot with depature time on the x-axis. This is units of seconds since midnight so it's hard to interpret." width="576"></p> </figure> </div> </div> </div> <p>Computing the difference between a pair of date-times yields a difftime (more on that in <a href="#sec-intervals" class="quarto-xref"><span>Section 17.4.3</span></a>). We can convert that to an <code>hms</code> object to get a more useful x-axis:</p> <div class="cell"> <div class="sourceCode" id="cb24"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights_dt</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/mutate.html">mutate</a></span><span class="op">(</span>dep_hour <span class="op">=</span> <span class="fu">hms</span><span class="fu">::</span><span class="fu"><a href="https://hms.tidyverse.org/reference/hms.html">as_hms</a></span><span class="op">(</span><span class="va">dep_time</span> <span class="op">-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/round_date.html">floor_date</a></span><span class="op">(</span><span class="va">dep_time</span>, <span class="st">"day"</span><span class="op">)</span><span class="op">)</span><span class="op">)</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/ggplot.html">ggplot</a></span><span class="op">(</span><span class="fu"><a href="https://ggplot2.tidyverse.org/reference/aes.html">aes</a></span><span class="op">(</span>x <span class="op">=</span> <span class="va">dep_hour</span><span class="op">)</span><span class="op">)</span> <span class="op">+</span></span> <span> <span class="fu"><a href="https://ggplot2.tidyverse.org/reference/geom_histogram.html">geom_freqpoly</a></span><span class="op">(</span>binwidth <span class="op">=</span> <span class="fl">60</span> <span class="op">*</span> <span class="fl">30</span><span class="op">)</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> <div class="cell-output-display"> <div> <figure class="figure"><p><img src="datetimes_files/figure-html/unnamed-chunk-26-1.png" class="img-fluid figure-img" alt="A line plot with depature time (midnight to midnight) on the x-axis and number of flights on the y-axis (0 to 15,000). There are very few (<100) flights before 5am. The number of flights then rises rapidly to 12,000 / hour, peaking at 15,000 at 9am, before falling to around 8,000 / hour for 10am to 2pm. Number of flights then increases to around 12,000 per hour until 8pm, when they rapidly drop again. " width="576"></p> </figure> </div> </div> </div> </section><section id="modifying-components" class="level3" data-number="17.3.3"><h3 data-number="17.3.3" class="anchored" data-anchor-id="modifying-components"> <span class="header-section-number">17.3.3</span> Modifying components</h3> <p>You can also use each accessor function to modify the components of a date/time. This doesn’t come up much in data analysis, but can be useful when cleaning data that has clearly incorrect dates.</p> <div class="cell"> <div class="sourceCode" id="cb25"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="op">(</span><span class="va">datetime</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd_hms.html">ymd_hms</a></span><span class="op">(</span><span class="st">"2026-07-08 12:34:56"</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> [1] "2026-07-08 12:34:56 UTC"</span></span> <span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/year.html">year</a></span><span class="op">(</span><span class="va">datetime</span><span class="op">)</span> <span class="op"><-</span> <span class="fl">2030</span></span> <span><span class="va">datetime</span></span> <span><span class="co">#> [1] "2030-07-08 12:34:56 UTC"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/month.html">month</a></span><span class="op">(</span><span class="va">datetime</span><span class="op">)</span> <span class="op"><-</span> <span class="fl">01</span></span> <span><span class="va">datetime</span></span> <span><span class="co">#> [1] "2030-01-08 12:34:56 UTC"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/hour.html">hour</a></span><span class="op">(</span><span class="va">datetime</span><span class="op">)</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/hour.html">hour</a></span><span class="op">(</span><span class="va">datetime</span><span class="op">)</span> <span class="op">+</span> <span class="fl">1</span></span> <span><span class="va">datetime</span></span> <span><span class="co">#> [1] "2030-01-08 13:34:56 UTC"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Alternatively, rather than modifying an existing variable, you can create a new date-time with <code><a href="https://rdrr.io/r/stats/update.html">update()</a></code>. This also allows you to set multiple values in one step:</p> <div class="cell"> <div class="sourceCode" id="cb26"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://rdrr.io/r/stats/update.html">update</a></span><span class="op">(</span><span class="va">datetime</span>, year <span class="op">=</span> <span class="fl">2030</span>, month <span class="op">=</span> <span class="fl">2</span>, mday <span class="op">=</span> <span class="fl">2</span>, hour <span class="op">=</span> <span class="fl">2</span><span class="op">)</span></span> <span><span class="co">#> [1] "2030-02-02 02:34:56 UTC"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>If values are too big, they will roll-over:</p> <div class="cell"> <div class="sourceCode" id="cb27"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://rdrr.io/r/stats/update.html">update</a></span><span class="op">(</span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="st">"2023-02-01"</span><span class="op">)</span>, mday <span class="op">=</span> <span class="fl">30</span><span class="op">)</span></span> <span><span class="co">#> [1] "2023-03-02"</span></span> <span><span class="fu"><a href="https://rdrr.io/r/stats/update.html">update</a></span><span class="op">(</span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="st">"2023-02-01"</span><span class="op">)</span>, hour <span class="op">=</span> <span class="fl">400</span><span class="op">)</span></span> <span><span class="co">#> [1] "2023-02-17 16:00:00 UTC"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> </section><section id="exercises-1" class="level3" data-number="17.3.4"><h3 data-number="17.3.4" class="anchored" data-anchor-id="exercises-1"> <span class="header-section-number">17.3.4</span> Exercises</h3> <ol type="1"> <li><p>How does the distribution of flight times within a day change over the course of the year?</p></li> <li><p>Compare <code>dep_time</code>, <code>sched_dep_time</code> and <code>dep_delay</code>. Are they consistent? Explain your findings.</p></li> <li><p>Compare <code>air_time</code> with the duration between the departure and arrival. Explain your findings. (Hint: consider the location of the airport.)</p></li> <li><p>How does the average delay time change over the course of a day? Should you use <code>dep_time</code> or <code>sched_dep_time</code>? Why?</p></li> <li><p>On what day of the week should you leave if you want to minimise the chance of a delay?</p></li> <li><p>What makes the distribution of <code>diamonds$carat</code> and <code>flights$sched_dep_time</code> similar?</p></li> <li><p>Confirm our hypothesis that the early departures of flights in minutes 20-30 and 50-60 are caused by scheduled flights that leave early. Hint: create a binary variable that tells you whether or not a flight was delayed.</p></li> </ol></section></section><section id="time-spans" class="level2" data-number="17.4"><h2 data-number="17.4" class="anchored" data-anchor-id="time-spans"> <span class="header-section-number">17.4</span> Time spans</h2> <p>Next you’ll learn about how arithmetic with dates works, including subtraction, addition, and division. Along the way, you’ll learn about three important classes that represent time spans:</p> <ul> <li> <strong>Durations</strong>, which represent an exact number of seconds.</li> <li> <strong>Periods</strong>, which represent human units like weeks and months.</li> <li> <strong>Intervals</strong>, which represent a starting and ending point.</li> </ul> <p>How do you pick between duration, periods, and intervals? As always, pick the simplest data structure that solves your problem. If you only care about physical time, use a duration; if you need to add human times, use a period; if you need to figure out how long a span is in human units, use an interval.</p> <section id="durations" class="level3" data-number="17.4.1"><h3 data-number="17.4.1" class="anchored" data-anchor-id="durations"> <span class="header-section-number">17.4.1</span> Durations</h3> <p>In R, when you subtract two dates, you get a difftime object:</p> <div class="cell"> <div class="sourceCode" id="cb28"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co"># How old is Hadley?</span></span> <span><span class="va">h_age</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/now.html">today</a></span><span class="op">(</span><span class="op">)</span> <span class="op">-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="st">"1979-10-14"</span><span class="op">)</span></span> <span><span class="va">h_age</span></span> <span><span class="co">#> Time difference of 16568 days</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>A <code>difftime</code> class object records a time span of seconds, minutes, hours, days, or weeks. This ambiguity can make difftimes a little painful to work with, so lubridate provides an alternative which always uses seconds: the <strong>duration</strong>.</p> <div class="cell"> <div class="sourceCode" id="cb29"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/as.duration.html">as.duration</a></span><span class="op">(</span><span class="va">h_age</span><span class="op">)</span></span> <span><span class="co">#> [1] "1431475200s (~45.36 years)"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Durations come with a bunch of convenient constructors:</p> <div class="cell"> <div class="sourceCode" id="cb30"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">dseconds</a></span><span class="op">(</span><span class="fl">15</span><span class="op">)</span></span> <span><span class="co">#> [1] "15s"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">dminutes</a></span><span class="op">(</span><span class="fl">10</span><span class="op">)</span></span> <span><span class="co">#> [1] "600s (~10 minutes)"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">dhours</a></span><span class="op">(</span><span class="fu"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op">(</span><span class="fl">12</span>, <span class="fl">24</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> [1] "43200s (~12 hours)" "86400s (~1 days)"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">ddays</a></span><span class="op">(</span><span class="fl">0</span><span class="op">:</span><span class="fl">5</span><span class="op">)</span></span> <span><span class="co">#> [1] "0s" "86400s (~1 days)" "172800s (~2 days)"</span></span> <span><span class="co">#> [4] "259200s (~3 days)" "345600s (~4 days)" "432000s (~5 days)"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">dweeks</a></span><span class="op">(</span><span class="fl">3</span><span class="op">)</span></span> <span><span class="co">#> [1] "1814400s (~3 weeks)"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">dyears</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="co">#> [1] "31557600s (~1 years)"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Durations always record the time span in seconds. Larger units are created by converting minutes, hours, days, weeks, and years to seconds: 60 seconds in a minute, 60 minutes in an hour, 24 hours in a day, and 7 days in a week. Larger time units are more problematic. A year uses the “average” number of days in a year, i.e. 365.25. There’s no way to convert a month to a duration, because there’s just too much variation.</p> <p>You can add and multiply durations:</p> <div class="cell"> <div class="sourceCode" id="cb31"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fl">2</span> <span class="op">*</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">dyears</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="co">#> [1] "63115200s (~2 years)"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">dyears</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">dweeks</a></span><span class="op">(</span><span class="fl">12</span><span class="op">)</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">dhours</a></span><span class="op">(</span><span class="fl">15</span><span class="op">)</span></span> <span><span class="co">#> [1] "38869200s (~1.23 years)"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>You can add and subtract durations to and from days:</p> <div class="cell"> <div class="sourceCode" id="cb32"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">tomorrow</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/now.html">today</a></span><span class="op">(</span><span class="op">)</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">ddays</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="va">last_year</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/now.html">today</a></span><span class="op">(</span><span class="op">)</span> <span class="op">-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">dyears</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>However, because durations represent an exact number of seconds, sometimes you might get an unexpected result:</p> <div class="cell"> <div class="sourceCode" id="cb33"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">one_am</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd_hms.html">ymd_hms</a></span><span class="op">(</span><span class="st">"2026-03-08 01:00:00"</span>, tz <span class="op">=</span> <span class="st">"America/New_York"</span><span class="op">)</span></span> <span></span> <span><span class="va">one_am</span></span> <span><span class="co">#> [1] "2026-03-08 01:00:00 EST"</span></span> <span><span class="va">one_am</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">ddays</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="co">#> [1] "2026-03-09 02:00:00 EDT"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Why is one day after 1am March 8, 2am March 9? If you look carefully at the date you might also notice that the time zones have changed. March 8 only has 23 hours because it’s when DST starts, so if we add a full days worth of seconds we end up with a different time.</p> </section><section id="periods" class="level3" data-number="17.4.2"><h3 data-number="17.4.2" class="anchored" data-anchor-id="periods"> <span class="header-section-number">17.4.2</span> Periods</h3> <p>To solve this problem, lubridate provides <strong>periods</strong>. Periods are time spans but don’t have a fixed length in seconds, instead they work with “human” times, like days and months. That allows them to work in a more intuitive way:</p> <div class="cell"> <div class="sourceCode" id="cb34"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">one_am</span></span> <span><span class="co">#> [1] "2026-03-08 01:00:00 EST"</span></span> <span><span class="va">one_am</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">days</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="co">#> [1] "2026-03-09 01:00:00 EDT"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Like durations, periods can be created with a number of friendly constructor functions.</p> <div class="cell"> <div class="sourceCode" id="cb35"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">hours</a></span><span class="op">(</span><span class="fu"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op">(</span><span class="fl">12</span>, <span class="fl">24</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> [1] "12H 0M 0S" "24H 0M 0S"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">days</a></span><span class="op">(</span><span class="fl">7</span><span class="op">)</span></span> <span><span class="co">#> [1] "7d 0H 0M 0S"</span></span> <span><span class="fu"><a href="https://rdrr.io/r/base/weekday.POSIXt.html">months</a></span><span class="op">(</span><span class="fl">1</span><span class="op">:</span><span class="fl">6</span><span class="op">)</span></span> <span><span class="co">#> [1] "1m 0d 0H 0M 0S" "2m 0d 0H 0M 0S" "3m 0d 0H 0M 0S" "4m 0d 0H 0M 0S"</span></span> <span><span class="co">#> [5] "5m 0d 0H 0M 0S" "6m 0d 0H 0M 0S"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>You can add and multiply periods:</p> <div class="cell"> <div class="sourceCode" id="cb36"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fl">10</span> <span class="op">*</span> <span class="op">(</span><span class="fu"><a href="https://rdrr.io/r/base/weekday.POSIXt.html">months</a></span><span class="op">(</span><span class="fl">6</span><span class="op">)</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">days</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> [1] "60m 10d 0H 0M 0S"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">days</a></span><span class="op">(</span><span class="fl">50</span><span class="op">)</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">hours</a></span><span class="op">(</span><span class="fl">25</span><span class="op">)</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">minutes</a></span><span class="op">(</span><span class="fl">2</span><span class="op">)</span></span> <span><span class="co">#> [1] "50d 25H 2M 0S"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>And of course, add them to dates. Compared to durations, periods are more likely to do what you expect:</p> <div class="cell"> <div class="sourceCode" id="cb37"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co"># A leap year</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="st">"2024-01-01"</span><span class="op">)</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">dyears</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="co">#> [1] "2024-12-31 06:00:00 UTC"</span></span> <span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="st">"2024-01-01"</span><span class="op">)</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">years</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="co">#> [1] "2025-01-01"</span></span> <span></span> <span><span class="co"># Daylight saving time</span></span> <span><span class="va">one_am</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/duration.html">ddays</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="co">#> [1] "2026-03-09 02:00:00 EDT"</span></span> <span><span class="va">one_am</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">days</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="co">#> [1] "2026-03-09 01:00:00 EDT"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Let’s use periods to fix an oddity related to our flight dates. Some planes appear to have arrived at their destination <em>before</em> they departed from New York City.</p> <div class="cell"> <div class="sourceCode" id="cb38"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights_dt</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/filter.html">filter</a></span><span class="op">(</span><span class="va">arr_time</span> <span class="op"><</span> <span class="va">dep_time</span><span class="op">)</span> </span> <span><span class="co">#> # A tibble: 10,633 × 9</span></span> <span><span class="co">#> origin dest dep_delay arr_delay dep_time sched_dep_time </span></span> <span><span class="co">#> <chr> <chr> <dbl> <dbl> <dttm> <dttm> </span></span> <span><span class="co">#> 1 EWR BQN 9 -4 2013-01-01 19:29:00 2013-01-01 19:20:00</span></span> <span><span class="co">#> 2 JFK DFW 59 NA 2013-01-01 19:39:00 2013-01-01 18:40:00</span></span> <span><span class="co">#> 3 EWR TPA -2 9 2013-01-01 20:58:00 2013-01-01 21:00:00</span></span> <span><span class="co">#> 4 EWR SJU -6 -12 2013-01-01 21:02:00 2013-01-01 21:08:00</span></span> <span><span class="co">#> 5 EWR SFO 11 -14 2013-01-01 21:08:00 2013-01-01 20:57:00</span></span> <span><span class="co">#> 6 LGA FLL -10 -2 2013-01-01 21:20:00 2013-01-01 21:30:00</span></span> <span><span class="co">#> # ℹ 10,627 more rows</span></span> <span><span class="co">#> # ℹ 3 more variables: arr_time <dttm>, sched_arr_time <dttm>, …</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>These are overnight flights. We used the same date information for both the departure and the arrival times, but these flights arrived on the following day. We can fix this by adding <code>days(1)</code> to the arrival time of each overnight flight.</p> <div class="cell"> <div class="sourceCode" id="cb39"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights_dt</span> <span class="op"><-</span> <span class="va">flights_dt</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/mutate.html">mutate</a></span><span class="op">(</span></span> <span> overnight <span class="op">=</span> <span class="va">arr_time</span> <span class="op"><</span> <span class="va">dep_time</span>,</span> <span> arr_time <span class="op">=</span> <span class="va">arr_time</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">days</a></span><span class="op">(</span><span class="va">overnight</span><span class="op">)</span>,</span> <span> sched_arr_time <span class="op">=</span> <span class="va">sched_arr_time</span> <span class="op">+</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">days</a></span><span class="op">(</span><span class="va">overnight</span><span class="op">)</span></span> <span> <span class="op">)</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Now all of our flights obey the laws of physics.</p> <div class="cell"> <div class="sourceCode" id="cb40"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">flights_dt</span> <span class="op">|></span> </span> <span> <span class="fu"><a href="https://dplyr.tidyverse.org/reference/filter.html">filter</a></span><span class="op">(</span><span class="va">arr_time</span> <span class="op"><</span> <span class="va">dep_time</span><span class="op">)</span> </span> <span><span class="co">#> # A tibble: 0 × 10</span></span> <span><span class="co">#> # ℹ 10 variables: origin <chr>, dest <chr>, dep_delay <dbl>,</span></span> <span><span class="co">#> # arr_delay <dbl>, dep_time <dttm>, sched_dep_time <dttm>, …</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> </section><section id="sec-intervals" class="level3" data-number="17.4.3"><h3 data-number="17.4.3" class="anchored" data-anchor-id="sec-intervals"> <span class="header-section-number">17.4.3</span> Intervals</h3> <p>What does <code>dyears(1) / ddays(365)</code> return? It’s not quite one, because <code><a href="https://lubridate.tidyverse.org/reference/duration.html">dyears()</a></code> is defined as the number of seconds per average year, which is 365.25 days.</p> <p>What does <code>years(1) / days(1)</code> return? Well, if the year was 2015 it should return 365, but if it was 2016, it should return 366! There’s not quite enough information for lubridate to give a single clear answer. What it does instead is give an estimate:</p> <div class="cell"> <div class="sourceCode" id="cb41"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">years</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span> <span class="op">/</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">days</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="co">#> [1] 365.25</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>If you want a more accurate measurement, you’ll have to use an <strong>interval</strong>. An interval is a pair of starting and ending date times, or you can think of it as a duration with a starting point.</p> <p>You can create an interval by writing <code>start %--% end</code>:</p> <div class="cell"> <div class="sourceCode" id="cb42"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">y2023</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="st">"2023-01-01"</span><span class="op">)</span> <span class="op"><a href="https://lubridate.tidyverse.org/reference/interval.html">%--%</a></span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="st">"2024-01-01"</span><span class="op">)</span></span> <span><span class="va">y2024</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="st">"2024-01-01"</span><span class="op">)</span> <span class="op"><a href="https://lubridate.tidyverse.org/reference/interval.html">%--%</a></span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd.html">ymd</a></span><span class="op">(</span><span class="st">"2025-01-01"</span><span class="op">)</span></span> <span></span> <span><span class="va">y2023</span></span> <span><span class="co">#> [1] 2023-01-01 UTC--2024-01-01 UTC</span></span> <span><span class="va">y2024</span></span> <span><span class="co">#> [1] 2024-01-01 UTC--2025-01-01 UTC</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>You could then divide it by <code><a href="https://lubridate.tidyverse.org/reference/period.html">days()</a></code> to find out how many days fit in the year:</p> <div class="cell"> <div class="sourceCode" id="cb43"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">y2023</span> <span class="op">/</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">days</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="co">#> [1] 365</span></span> <span><span class="va">y2024</span> <span class="op">/</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/period.html">days</a></span><span class="op">(</span><span class="fl">1</span><span class="op">)</span></span> <span><span class="co">#> [1] 366</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> </section><section id="exercises-2" class="level3" data-number="17.4.4"><h3 data-number="17.4.4" class="anchored" data-anchor-id="exercises-2"> <span class="header-section-number">17.4.4</span> Exercises</h3> <ol type="1"> <li><p>Explain <code>days(!overnight)</code> and <code>days(overnight)</code> to someone who has just started learning R. What is the key fact you need to know?</p></li> <li><p>Create a vector of dates giving the first day of every month in 2015. Create a vector of dates giving the first day of every month in the <em>current</em> year.</p></li> <li><p>Write a function that given your birthday (as a date), returns how old you are in years.</p></li> <li><p>Why can’t <code>(today() %--% (today() + years(1))) / months(1)</code> work?</p></li> </ol></section></section><section id="time-zones" class="level2" data-number="17.5"><h2 data-number="17.5" class="anchored" data-anchor-id="time-zones"> <span class="header-section-number">17.5</span> Time zones</h2> <p>Time zones are an enormously complicated topic because of their interaction with geopolitical entities. Fortunately we don’t need to dig into all the details as they’re not all important for data analysis, but there are a few challenges we’ll need to tackle head on.</p> <!--# https://www.ietf.org/timezones/tzdb-2018a/theory.html --> <p>The first challenge is that everyday names of time zones tend to be ambiguous. For example, if you’re American you’re probably familiar with EST, or Eastern Standard Time. However, both Australia and Canada also have EST! To avoid confusion, R uses the international standard IANA time zones. These use a consistent naming scheme <code>{area}/{location}</code>, typically in the form <code>{continent}/{city}</code> or <code>{ocean}/{city}</code>. Examples include “America/New_York”, “Europe/Paris”, and “Pacific/Auckland”.</p> <p>You might wonder why the time zone uses a city, when typically you think of time zones as associated with a country or region within a country. This is because the IANA database has to record decades worth of time zone rules. Over the course of decades, countries change names (or break apart) fairly frequently, but city names tend to stay the same. Another problem is that the name needs to reflect not only the current behavior, but also the complete history. For example, there are time zones for both “America/New_York” and “America/Detroit”. These cities both currently use Eastern Standard Time but in 1969-1972 Michigan (the state in which Detroit is located), did not follow DST, so it needs a different name. It’s worth reading the raw time zone database (available at <a href="https://www.iana.org/time-zones" class="uri">https://www.iana.org/time-zones</a>) just to read some of these stories!</p> <p>You can find out what R thinks your current time zone is with <code><a href="https://rdrr.io/r/base/timezones.html">Sys.timezone()</a></code>:</p> <div class="cell"> <div class="sourceCode" id="cb44"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://rdrr.io/r/base/timezones.html">Sys.timezone</a></span><span class="op">(</span><span class="op">)</span></span> <span><span class="co">#> [1] "UTC"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>(If R doesn’t know, you’ll get an <code>NA</code>.)</p> <p>And see the complete list of all time zone names with <code><a href="https://rdrr.io/r/base/timezones.html">OlsonNames()</a></code>:</p> <div class="cell"> <div class="sourceCode" id="cb45"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu"><a href="https://rdrr.io/r/base/length.html">length</a></span><span class="op">(</span><span class="fu"><a href="https://rdrr.io/r/base/timezones.html">OlsonNames</a></span><span class="op">(</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> [1] 597</span></span> <span><span class="fu"><a href="https://rdrr.io/r/utils/head.html">head</a></span><span class="op">(</span><span class="fu"><a href="https://rdrr.io/r/base/timezones.html">OlsonNames</a></span><span class="op">(</span><span class="op">)</span><span class="op">)</span></span> <span><span class="co">#> [1] "Africa/Abidjan" "Africa/Accra" "Africa/Addis_Ababa"</span></span> <span><span class="co">#> [4] "Africa/Algiers" "Africa/Asmara" "Africa/Asmera"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>In R, the time zone is an attribute of the date-time that only controls printing. For example, these three objects represent the same instant in time:</p> <div class="cell"> <div class="sourceCode" id="cb46"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">x1</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd_hms.html">ymd_hms</a></span><span class="op">(</span><span class="st">"2024-06-01 12:00:00"</span>, tz <span class="op">=</span> <span class="st">"America/New_York"</span><span class="op">)</span></span> <span><span class="va">x1</span></span> <span><span class="co">#> [1] "2024-06-01 12:00:00 EDT"</span></span> <span></span> <span><span class="va">x2</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd_hms.html">ymd_hms</a></span><span class="op">(</span><span class="st">"2024-06-01 18:00:00"</span>, tz <span class="op">=</span> <span class="st">"Europe/Copenhagen"</span><span class="op">)</span></span> <span><span class="va">x2</span></span> <span><span class="co">#> [1] "2024-06-01 18:00:00 CEST"</span></span> <span></span> <span><span class="va">x3</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/ymd_hms.html">ymd_hms</a></span><span class="op">(</span><span class="st">"2024-06-02 04:00:00"</span>, tz <span class="op">=</span> <span class="st">"Pacific/Auckland"</span><span class="op">)</span></span> <span><span class="va">x3</span></span> <span><span class="co">#> [1] "2024-06-02 04:00:00 NZST"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>You can verify that they’re the same time using subtraction:</p> <div class="cell"> <div class="sourceCode" id="cb47"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">x1</span> <span class="op">-</span> <span class="va">x2</span></span> <span><span class="co">#> Time difference of 0 secs</span></span> <span><span class="va">x1</span> <span class="op">-</span> <span class="va">x3</span></span> <span><span class="co">#> Time difference of 0 secs</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>Unless otherwise specified, lubridate always uses UTC. UTC (Coordinated Universal Time) is the standard time zone used by the scientific community and is roughly equivalent to GMT (Greenwich Mean Time). It does not have DST, which makes a convenient representation for computation. Operations that combine date-times, like <code><a href="https://rdrr.io/r/base/c.html">c()</a></code>, will often drop the time zone. In that case, the date-times will display in the time zone of the first element:</p> <div class="cell"> <div class="sourceCode" id="cb48"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">x4</span> <span class="op"><-</span> <span class="fu"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op">(</span><span class="va">x1</span>, <span class="va">x2</span>, <span class="va">x3</span><span class="op">)</span></span> <span><span class="va">x4</span></span> <span><span class="co">#> [1] "2024-06-01 12:00:00 EDT" "2024-06-01 12:00:00 EDT"</span></span> <span><span class="co">#> [3] "2024-06-01 12:00:00 EDT"</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>You can change the time zone in two ways:</p> <ul> <li> <p>Keep the instant in time the same, and change how it’s displayed. Use this when the instant is correct, but you want a more natural display.</p> <div class="cell"> <div class="sourceCode" id="cb49"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">x4a</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/with_tz.html">with_tz</a></span><span class="op">(</span><span class="va">x4</span>, tzone <span class="op">=</span> <span class="st">"Australia/Lord_Howe"</span><span class="op">)</span></span> <span><span class="va">x4a</span></span> <span><span class="co">#> [1] "2024-06-02 02:30:00 +1030" "2024-06-02 02:30:00 +1030"</span></span> <span><span class="co">#> [3] "2024-06-02 02:30:00 +1030"</span></span> <span><span class="va">x4a</span> <span class="op">-</span> <span class="va">x4</span></span> <span><span class="co">#> Time differences in secs</span></span> <span><span class="co">#> [1] 0 0 0</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> <p>(This also illustrates another challenge of times zones: they’re not all integer hour offsets!)</p> </li> <li> <p>Change the underlying instant in time. Use this when you have an instant that has been labelled with the incorrect time zone, and you need to fix it.</p> <div class="cell"> <div class="sourceCode" id="cb50"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va">x4b</span> <span class="op"><-</span> <span class="fu"><a href="https://lubridate.tidyverse.org/reference/force_tz.html">force_tz</a></span><span class="op">(</span><span class="va">x4</span>, tzone <span class="op">=</span> <span class="st">"Australia/Lord_Howe"</span><span class="op">)</span></span> <span><span class="va">x4b</span></span> <span><span class="co">#> [1] "2024-06-01 12:00:00 +1030" "2024-06-01 12:00:00 +1030"</span></span> <span><span class="co">#> [3] "2024-06-01 12:00:00 +1030"</span></span> <span><span class="va">x4b</span> <span class="op">-</span> <span class="va">x4</span></span> <span><span class="co">#> Time differences in hours</span></span> <span><span class="co">#> [1] -14.5 -14.5 -14.5</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> </div> </li> </ul></section><section id="summary" class="level2" data-number="17.6"><h2 data-number="17.6" class="anchored" data-anchor-id="summary"> <span class="header-section-number">17.6</span> Summary</h2> <p>This chapter has introduced you to the tools that lubridate provides to help you work with date-time data. Working with dates and times can seem harder than necessary, but hopefully this chapter has helped you see why — date-times are more complex than they seem at first glance, and handling every possible situation adds complexity. Even if your data never crosses a day light savings boundary or involves a leap year, the functions need to be able to handle it.</p> <p>The next chapter gives a round up of missing values. You’ve seen them in a few places and have no doubt encounter in your own analysis, and it’s now time to provide a grab bag of useful techniques for dealing with them.</p> </section><section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes"><hr> <ol> <li id="fn1"><p>A year is a leap year if it’s divisible by 4, unless it’s also divisible by 100, except if it’s also divisible by 400. In other words, in every set of 400 years, there’s 97 leap years.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li> <li id="fn2"><p><a href="https://xkcd.com/1179/" class="uri">https://xkcd.com/1179/</a><a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li> <li id="fn3"><p>You might wonder what UTC stands for. It’s a compromise between the English “Coordinated Universal Time” and French “Temps Universel Coordonné”.<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li> <li id="fn4"><p>No prizes for guessing which country came up with the longitude system.<a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li> </ol></section></main><!-- /main --><script id="quarto-html-after-body" type="application/javascript"> window.document.addEventListener("DOMContentLoaded", function (event) { const toggleBodyColorMode = (bsSheetEl) => { const mode = bsSheetEl.getAttribute("data-mode"); const bodyEl = window.document.querySelector("body"); if (mode === "dark") { bodyEl.classList.add("quarto-dark"); bodyEl.classList.remove("quarto-light"); } else { bodyEl.classList.add("quarto-light"); bodyEl.classList.remove("quarto-dark"); } } const toggleBodyColorPrimary = () => { const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); if (bsSheetEl) { toggleBodyColorMode(bsSheetEl); } } toggleBodyColorPrimary(); const icon = ""; const anchorJS = new window.AnchorJS(); anchorJS.options = { placement: 'right', icon: icon }; anchorJS.add('.anchored'); const isCodeAnnotation = (el) => { for (const clz of el.classList) { if (clz.startsWith('code-annotation-')) { return true; } } return false; } const onCopySuccess = function(e) { // button target const button = e.trigger; // don't keep focus button.blur(); // flash "checked" button.classList.add('code-copy-button-checked'); var currentTitle = button.getAttribute("title"); button.setAttribute("title", "Copied!"); let tooltip; if (window.bootstrap) { button.setAttribute("data-bs-toggle", "tooltip"); button.setAttribute("data-bs-placement", "left"); button.setAttribute("data-bs-title", "Copied!"); tooltip = new bootstrap.Tooltip(button, { trigger: "manual", customClass: "code-copy-button-tooltip", offset: [0, -8]}); tooltip.show(); } setTimeout(function() { if (tooltip) { tooltip.hide(); button.removeAttribute("data-bs-title"); button.removeAttribute("data-bs-toggle"); button.removeAttribute("data-bs-placement"); } button.setAttribute("title", currentTitle); button.classList.remove('code-copy-button-checked'); }, 1000); // clear code selection e.clearSelection(); } const getTextToCopy = function(trigger) { const codeEl = trigger.previousElementSibling.cloneNode(true); for (const childEl of codeEl.children) { if (isCodeAnnotation(childEl)) { childEl.remove(); } } return codeEl.innerText; } const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', { text: getTextToCopy }); clipboard.on('success', onCopySuccess); if (window.document.getElementById('quarto-embedded-source-code-modal')) { const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', { text: getTextToCopy, container: window.document.getElementById('quarto-embedded-source-code-modal') }); clipboardModal.on('success', onCopySuccess); } var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//); var mailtoRegex = new RegExp(/^mailto:/); var filterRegex = new RegExp("https:\/\/r4ds\.hadley\.nz\/"); var isInternal = (href) => { return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href); } // Inspect non-navigation links and adorn them if external var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)'); for (var i=0; i<links.length; i++) { const link = links[i]; if (!isInternal(link.href)) { // undo the damage that might have been done by quarto-nav.js in the case of // links that we want to consider external if (link.dataset.originalHref !== undefined) { link.href = link.dataset.originalHref; } } } function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) { const config = { allowHTML: true, maxWidth: 500, delay: 100, arrow: false, appendTo: function(el) { return el.parentElement; }, interactive: true, interactiveBorder: 10, theme: 'quarto', placement: 'bottom-start', }; if (contentFn) { config.content = contentFn; } if (onTriggerFn) { config.onTrigger = onTriggerFn; } if (onUntriggerFn) { config.onUntrigger = onUntriggerFn; } window.tippy(el, config); } const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); for (var i=0; i<noterefs.length; i++) { const ref = noterefs[i]; tippyHover(ref, function() { // use id or data attribute instead here let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); try { href = new URL(href).hash; } catch {} const id = href.replace(/^#\/?/, ""); const note = window.document.getElementById(id); if (note) { return note.innerHTML; } else { return ""; } }); } const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { // Strip column container classes const stripColumnClz = (el) => { el.classList.remove("page-full", "page-columns"); if (el.children) { for (const child of el.children) { stripColumnClz(child); } } } stripColumnClz(note) if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { container.appendChild(note.children[0].cloneNode(true)); for (let i = 1; i < note.children.length; i++) { const child = note.children[i]; if (child.tagName === "P" && child.innerText === "") { continue; } else { container.appendChild(child.cloneNode(true)); break; } } if (window.Quarto?.typesetMath) { window.Quarto.typesetMath(container); } return container.innerHTML } else { if (window.Quarto?.typesetMath) { window.Quarto.typesetMath(note); } return note.innerHTML; } } else { // Remove any anchor links if they are present const anchorLink = note.querySelector('a.anchorjs-link'); if (anchorLink) { anchorLink.remove(); } if (window.Quarto?.typesetMath) { window.Quarto.typesetMath(note); } if (note.classList.contains("callout")) { return note.outerHTML; } else { return note.innerHTML; } } } for (var i=0; i<xrefs.length; i++) { const xref = xrefs[i]; tippyHover(xref, undefined, function(instance) { instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; if (url.startsWith('#')) { hash = url; } else { try { hash = new URL(url).hash; } catch {} } if (hash) { const id = hash.replace(/^#\/?/, ""); const note = window.document.getElementById(id); if (note !== null) { try { const html = processXRef(id, note.cloneNode(true)); instance.setContent(html); } finally { instance.enable(); instance.show(); } } else { // See if we can fetch this fetch(url.split('#')[0]) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); const note = htmlDoc.getElementById(id); if (note !== null) { const html = processXRef(id, note); instance.setContent(html); } }).finally(() => { instance.enable(); instance.show(); }); } } else { // See if we can fetch a full url (with no hash to target) // This is a special case and we should probably do some content thinning / targeting fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); const note = htmlDoc.querySelector('main.content'); if (note !== null) { // This should only happen for chapter cross references // (since there is no id in the URL) // remove the first header if (note.children.length > 0 && note.children[0].tagName === "HEADER") { note.children[0].remove(); } const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { instance.enable(); instance.show(); }); } }, function(instance) { }); } let selectedAnnoteEl; const selectorForAnnotation = ( cell, annotation) => { let cellAttr = 'data-code-cell="' + cell + '"'; let lineAttr = 'data-code-annotation="' + annotation + '"'; const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; return selector; } const selectCodeLines = (annoteEl) => { const doc = window.document; const targetCell = annoteEl.getAttribute("data-target-cell"); const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); const lines = annoteSpan.getAttribute("data-code-lines").split(","); const lineIds = lines.map((line) => { return targetCell + "-" + line; }) let top = null; let height = null; let parent = null; if (lineIds.length > 0) { //compute the position of the single el (top and bottom and make a div) const el = window.document.getElementById(lineIds[0]); top = el.offsetTop; height = el.offsetHeight; parent = el.parentElement.parentElement; if (lineIds.length > 1) { const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); const bottom = lastEl.offsetTop + lastEl.offsetHeight; height = bottom - top; } if (top !== null && height !== null && parent !== null) { // cook up a div (if necessary) and position it let div = window.document.getElementById("code-annotation-line-highlight"); if (div === null) { div = window.document.createElement("div"); div.setAttribute("id", "code-annotation-line-highlight"); div.style.position = 'absolute'; parent.appendChild(div); } div.style.top = top - 2 + "px"; div.style.height = height + 4 + "px"; div.style.left = 0; let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); if (gutterDiv === null) { gutterDiv = window.document.createElement("div"); gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); gutterDiv.style.position = 'absolute'; const codeCell = window.document.getElementById(targetCell); const gutter = codeCell.querySelector('.code-annotation-gutter'); gutter.appendChild(gutterDiv); } gutterDiv.style.top = top - 2 + "px"; gutterDiv.style.height = height + 4 + "px"; } selectedAnnoteEl = annoteEl; } }; const unselectCodeLines = () => { const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; elementsIds.forEach((elId) => { const div = window.document.getElementById(elId); if (div) { div.remove(); } }); selectedAnnoteEl = undefined; }; // Handle positioning of the toggle window.addEventListener( "resize", throttle(() => { elRect = undefined; if (selectedAnnoteEl) { selectCodeLines(selectedAnnoteEl); } }, 10) ); function throttle(fn, ms) { let throttle = false; let timer; return (...args) => { if(!throttle) { // first call gets through fn.apply(this, args); throttle = true; } else { // all the others get throttled if(timer) clearTimeout(timer); // cancel #2 timer = setTimeout(() => { fn.apply(this, args); timer = throttle = false; }, ms); } }; } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { annoteDlNode.addEventListener('click', (event) => { const clickedEl = event.target; if (clickedEl !== selectedAnnoteEl) { unselectCodeLines(); const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); if (activeEl) { activeEl.classList.remove('code-annotation-active'); } selectCodeLines(clickedEl); clickedEl.classList.add('code-annotation-active'); } else { // Unselect the line unselectCodeLines(); clickedEl.classList.remove('code-annotation-active'); } }); } const findCites = (el) => { const parentEl = el.parentElement; if (parentEl) { const cites = parentEl.dataset.cites; if (cites) { return { el, cites: cites.split(' ') }; } else { return findCites(el.parentElement) } } else { return undefined; } }; var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); for (var i=0; i<bibliorefs.length; i++) { const ref = bibliorefs[i]; const citeInfo = findCites(ref); if (citeInfo) { tippyHover(citeInfo.el, function() { var popup = window.document.createElement('div'); citeInfo.cites.forEach(function(cite) { var citeDiv = window.document.createElement('div'); citeDiv.classList.add('hanging-indent'); citeDiv.classList.add('csl-entry'); var biblioDiv = window.document.getElementById('ref-' + cite); if (biblioDiv) { citeDiv.innerHTML = biblioDiv.innerHTML; } popup.appendChild(citeDiv); }); return popup.innerHTML; }); } } }); </script><nav class="page-navigation"><div class="nav-page nav-page-previous"> <a href="./factors.html" class="pagination-link" aria-label="Factors"> <i class="bi bi-arrow-left-short"></i> <span class="nav-page-text"><span class="chapter-number">16</span> <span class="chapter-title">Factors</span></span> </a> </div> <div class="nav-page nav-page-next"> <a href="./missing-values.html" class="pagination-link" aria-label="Missing values"> <span class="nav-page-text"><span class="chapter-number">18</span> <span class="chapter-title">Missing values</span></span> <i class="bi bi-arrow-right-short"></i> </a> </div> </nav> </div> <!-- /content --> <footer class="footer"><div class="nav-footer"> <div class="nav-footer-left"> <p>R for Data Science (2e) was written by Hadley Wickham, Mine Çetinkaya-Rundel, and Garrett Grolemund.</p> </div> <div class="nav-footer-center"> <div class="toc-actions d-sm-block d-md-none"><ul><li><a href="https://github.com/hadley/r4ds/edit/main/datetimes.qmd" class="toc-action"><i class="bi bi-github"></i>Edit this page</a></li><li><a href="https://github.com/hadley/r4ds/issues/new" class="toc-action"><i class="bi empty"></i>Report an issue</a></li></ul></div></div> <div class="nav-footer-right"> <p>This book was built with <a href="https://quarto.org/">Quarto</a>.</p> </div> </div> </footer> </body></html>