13  Dates

A date usually arrives as text. to_date reads one, and once a column holds a date there is a word for each part you might want out of it.

diary <- data.frame(
  g = c("a", "a", "b"),
  on_ = c("2026-01-02", "2026-01-05", "2026-01-06"),
  x = c(10, 20, 30),
  stringsAsFactors = FALSE
)

diary |>
  add(d = to_date(on_)) |>
  add(year = year(d), month = month(d), weekday = weekday(d))
g on_ x d year month weekday
a 2026-01-02 10 2026-01-02 2026 1 5
a 2026-01-05 20 2026-01-05 2026 1 1
b 2026-01-06 30 2026-01-06 2026 1 2
diary = pd.DataFrame({
    "g": ["a", "a", "b"],
    "on_": ["2026-01-02", "2026-01-05", "2026-01-06"],
    "x": [10, 20, 30],
})

(diary
 >> add(d = to_date(col.on_))
 >> add(year = year(col.d), month = month(col.d), weekday = weekday(col.d)))
g on_ x d year month weekday
a 2026-01-02 10 2026-01-02 2026 1 5
a 2026-01-05 20 2026-01-05 2026 1 1
b 2026-01-06 30 2026-01-06 2026 1 2

weekday counts Monday as 1, wherever you run it. That is the grammar’s numbering rather than the engine’s, and it has to be: asked plainly, one engine calls a Friday 5 and another calls it 4, and neither says anything is wrong.

13.1 The five parts

year, month, day, weekday and hour. Each one pulls a number out of a date, and each is named for what it returns.

diary |>
  add(on = to_date(on_)) |>
  add(y = year(on), m = month(on), d = day(on), wd = weekday(on)) |>
  pick(on_, y, m, d, wd)
on_ y m d wd
2026-01-02 2026 1 2 5
2026-01-05 2026 1 5 1
2026-01-06 2026 1 6 2
(diary
  >> add(on = to_date(col.on_))
  >> add(y = year(col.on), m = month(col.on), d = day(col.on), wd = weekday(col.on))
  >> pick(col.on_, col.y, col.m, col.d, col.wd))
on_ y m d wd
2026-01-02 2026 1 2 5
2026-01-05 2026 1 5 1
2026-01-06 2026 1 6 2

hour is the fifth, and it wants a value that carries a time. A plain date has no hour in it, so on the dates above it answers zero rather than refusing.

data.frame(at = "2026-01-02 14:30:00") |> add(h = hour(to_date(at))) |> pick(at, h)
at h
2026-01-02 14:30:00 0
pd.DataFrame({"at": ["2026-01-02 14:30:00"]}) >> add(h = hour(to_date(col.at))) >> pick(col.at, col.h)
at h
2026-01-02 14:30:00 0