How do Calendar and DateComponents work, and why can YYYY give the wrong year?
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.currentis Gregorian. PinCalendar(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
firstWeekdaymatter? 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? →