Dates and Times I

Storing, creating, displaying, and converting time.

Last Time

  1. Shortcut classes name common sets like digits.
  2. Anchors pin a pattern to the start or end.
  3. Grouping sets the scope of a quantifier.
  4. Alternation matches one pattern or another.

Key Ideas for Today

  1. A date-time counts seconds since 1970 (Unix time).
  2. Parsing turns text into a date-time.
  3. Getters and setters read and change its parts.
  4. Some parts, like months, are circular.

What are the results of the following operations?

t1 <- 2026-10-14+1
t2 <- 10/14-10/7
01:00

Agenda

  1. How does a computer Store dates and times?
  2. How do we Create dates and times?
  3. How do we Get and Set them?

Storing

Unix Time

A method to measure time as the number of seconds1 that have elapsed since midnight UTC on 1 January 1970, the Unix epoch.

Date Time (UTC) Unix Time
12:01 am Jan 1, 1970 60

Unix Time

A method to measure time as the number of seconds1 that have elapsed since midnight UTC on 1 January 1970, the Unix epoch.

Date Time (UTC) Unix Time
12:01 am Jan 1, 1970 60
12:01 am Jan 2, 1970 86460

Unix Time

A method to measure time as the number of seconds1 that have elapsed since midnight UTC on 1 January 1970, the Unix epoch.

Date Time (UTC) Unix Time
12:01 am Jan 1, 1970 60
12:01 am Jan 2, 1970 86460
7 pm Oct 14, 2026 (today at noon) 1792004400

Unix Time

A method to measure time as the number of seconds1 that have elapsed since midnight UTC on 1 January 1970, the Unix epoch.

Date Time (UTC) Unix Time
12:01 am Jan 1, 1970 60
12:01 am Jan 2, 1970 86460
7 pm Oct 14, 2026 (today at noon) 1792004400
5:55 pm Dec 7, 1941 −8993325700

https://www.unixtimestamp.com/

POSIXct

POSIXct (Portable Operating System Interface Calendar Time) is an atomic vector to store date-times that is built on top of a double vector.

now <- Sys.time()
now
[1] "2026-10-26 15:44:22 UTC"
class(now)
[1] "POSIXct" "POSIXt" 

Why not just use a double vector?

# it prints as a legible string
now
[1] "2026-10-26 15:44:22 UTC"
# while respecting artithmetic
now + 1
[1] "2026-10-26 15:44:23 UTC"
# and other sensible operations
round(now, units = "hours")
[1] "2026-10-26 16:00:00 UTC"
# and makes it easy to use other formats
format(now, "%m/%d/%y")
[1] "10/26/26"

Date

A simpler vector than POSIXct that stores date data without times. Created with as.Date().

halloween <- as.Date("2000-10-31")
class(halloween)
[1] "Date"
typeof(halloween)
[1] "double"
halloween
[1] "2000-10-31"

Creating

Creating date-time vectors

Use as.POSIXct() to create a date-time vector from a numeric (in Unix Time) or a string in a particular format.

Creating date-time vectors

Use as.POSIXct() to create a date-time vector from a numeric (in Unix Time) or a string in a particular format.

as.POSIXct(x = 60, tz = "UTC")
[1] "1970-01-01 00:01:00 UTC"
as.POSIXct(x = "1970-01-01 00:01:00", tz = "UTC")
[1] "1970-01-01 00:01:00 UTC"
as.POSIXct(x = "Jan 1, 1970 12:01 am",
           format = "%b %d, %Y %I:%M %p",
           tz = "UTC")
[1] "1970-01-01 00:01:00 UTC"

Formats: https://r4ds.hadley.nz/datetimes.html#tbl-date-formats

Creating with lubridate

as.POSIXct(x = "1970-01-01 00:01:00", tz = "UTC")
[1] "1970-01-01 00:01:00 UTC"

lubridate() has many functions that can parse the year (y), month (m), day (d), hour (h), minute (m), and second (s) components of a date-time string.

library(lubridate)
mdy_hm("Jan 1, 1970 12:01 am")
[1] "1970-01-01 00:01:00 UTC"
dmy_hm("1-1-1970 00:01")
[1] "1970-01-01 00:01:00 UTC"

Your Turn

Question: Which lubridate function parses each string?

  1. "14 October 2026"
  2. "10/14/26 9:00"
  3. "2026-10-14 12:00:00"
01:00

Parsing each string

dmy("14 October 2026") # question 1
[1] "2026-10-14"
mdy_hm("10/14/26 9:00") # question 2
[1] "2026-10-14 09:00:00 UTC"
ymd_hms("2026-10-14 12:00:00") # question 3
[1] "2026-10-14 12:00:00 UTC"

Getting and Setting

Getting

You can extract components of the date-time object using year(), month(), week(), day(), wday(), hour(), etc.

year(now)
[1] 2026
day(now)
[1] 26
wday(now)
[1] 2

Getting

You can extract components of the date-time object using year(), month(), week(), day(), wday(), hour(), etc.

year(now)
[1] 2026
day(now)
[1] 26
wday(now, label = TRUE)
[1] Mon
Levels: Sun < Mon < Tue < Wed < Thu < Fri < Sat

Getting

You can extract components of the date-time object using year(), month(), week(), day(), wday(), hour(), etc.

year(now)
[1] 2026
day(now)
[1] 26
wday(now, label = TRUE, abbr = FALSE)
[1] Monday
7 Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < ... < Saturday

Setting

You can set those same components in an existing date-time object using change-in-place notation.

year(now) <- 2027
now
[1] "2027-10-26 15:44:22 UTC"
wday(now, label = TRUE, abbr = FALSE)
[1] Tuesday
7 Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < ... < Saturday

Your Turn

Question: Write the (lines) of code necessary to determine:

  1. On which day of the week will New Years Eve fall this year?
  2. What day of the week was US Independence Day?
  3. Bonus What was the corresponding Unix time?
02:00

Your Turn: Solutions

wday(ymd("2026-12-31"), label = TRUE, abbr = FALSE) # question 1
[1] Thursday
7 Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < ... < Saturday
wday(ymd("2026-07-04"), label = TRUE, abbr = FALSE) # question 2
[1] Saturday
7 Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < ... < Saturday

Your Turn: Bonus Solution

as.numeric(ymd("2026-07-04")) # question 3: days, not seconds!
[1] 20638
as.numeric(ymd("2026-07-04", tz = "UTC")) # question 3: seconds
[1] 1783123200

Circular Data

Example: Circular Data

What is the average month of these observations?

# A tibble: 6 × 2
  month  year
  <dbl> <dbl>
1     2  2026
2     1  2026
3     2  2026
4    11  2025
5    12  2025
6    12  2025
df |>
  summarize(avg_month = mean(month))
# A tibble: 1 × 1
  avg_month
      <dbl>
1      6.67

Example: Circular Data

What is the month of the average of these dates?

df |>
  mutate(datetime = make_datetime(year = year,
                                  day = 15,
                                  month = month))
# A tibble: 6 × 3
  month  year datetime           
  <dbl> <dbl> <dttm>             
1     2  2026 2026-02-15 00:00:00
2     1  2026 2026-01-15 00:00:00
3     2  2026 2026-02-15 00:00:00
4    11  2025 2025-11-15 00:00:00
5    12  2025 2025-12-15 00:00:00
6    12  2025 2025-12-15 00:00:00

Example: Circular Data

What is the month of the average of these dates?

df |>
  mutate(datetime = make_datetime(year = year,
                                  day = 15,
                                  month = month)) |>
  summarize(avg_datetime = mean(datetime))
# A tibble: 1 × 1
  avg_datetime       
  <dttm>             
1 2026-01-04 20:00:00

Example: Circular Data

What is the month of the average of these dates?

df |>
  mutate(datetime = make_datetime(year = year,
                                  day = 15,
                                  month = month)) |>
  summarize(avg_datetime = mean(datetime)) |>
  mutate(mon_of_avg = month(avg_datetime))
# A tibble: 1 × 2
  avg_datetime        mon_of_avg
  <dttm>                   <dbl>
1 2026-01-04 20:00:00          1

Guess the Metaphor

A date-time is like a giant sundial: underneath it’s a single measurement, how far the shadow has travelled from a fixed origin, but we read it off the dial as hours and days. And like the dial, some parts wrap around: December sits right next to January.

Key Ideas for Today

  1. A date-time counts seconds since 1970 (Unix time).
  2. Parsing turns text into a date-time.
  3. Getters and setters read and change its parts.
  4. Some parts, like months, are circular.

For Next Time

  1. Sign up for Quiz 4 (10/19-10/20) on PrairieTest.
  2. Work on PS 4, due Saturday 10/17 at 11:59 pm.
  3. Do Project 3 now and ask for help.