How do Calendar and DateComponents work, and why can YYYY give the wrong year?

2.2.3 · L1 · Interview

Predict first

What does this print?

var cal = Calendar(identifier: .iso8601)
cal.timeZone = TimeZone(identifier: "UTC")!
let d = Date(timeIntervalSince1970: 1735516800)  // 2024-12-30
print(cal.component(.year, from: d), cal.component(.yearForWeekOfYear, from: d), cal.component(.weekOfYear, from: d))
  • 2024 2024 53
  • 2024 2025 1
  • 2025 2025 1

Predict first

What does this print?

let cal = Calendar(identifier: .gregorian)
var utc = cal
utc.timeZone = TimeZone(identifier: "UTC")!
print(utc.component(.weekday, from: Date(timeIntervalSince1970: 1735516800)))  // a Monday
  • 1
  • 2
  • 0

Mental model. The Date is a moment. The Calendar is a translator that turns it into “year, month, day” in one particular culture.

Calendar converts between an instant and its human parts. dateComponents(_:from:) pulls fields out of a Date; date(from:) builds a Date from fields. DateComponents is just a bag of optional fields. It is not a date until a calendar and a zone resolve it. Calendar.current is not always Gregorian: it follows the user’s settings (Buddhist, Japanese, Hebrew and so on).

Weeks have their own year. A date near New Year can belong to week 1 of next year, so yearForWeekOfYear differs from year. Formatting with the week-based year (YYYY) is the classic late-December bug. For ISO weeks use Calendar(identifier: .iso8601).

30 December 2024 is in the year 2024, but its ISO week is week 1 of 2025. That is why a YYYY format shows 2025.

Gregorian weekdays count from Sunday = 1, so Monday is 2.

Common traps

  • Assuming Calendar.current is Gregorian. Pin Calendar(identifier: .gregorian) for logic that must be Gregorian.
  • Weekday numbers. In Gregorian, Sunday is 1, so Monday is 2, not 1.

They might follow up with

  • Why does firstWeekday matter? It changes which week a date lands in, and so week-of-year results.
  • How do you make a date from parts? cal.date(from: DateComponents(year: 2024, month: 3, day: 9)), with the calendar’s time zone set first.

Related questions

  • 2.2.4 Why is date + 86,400 seconds not tomorrow?
  • 2.2.8 What goes wrong with DateFormatter, and how do you parse a fixed format safely?

← How do you handle time zones: what do you store, send and show?   Why is date + 86,400 seconds not tomorrow? →