What goes wrong with DateFormatter, and how do you parse a fixed format safely?
Predict first
What does this print?
let f = DateFormatter()
f.locale = Locale(identifier: "en_US_POSIX")
f.timeZone = TimeZone(identifier: "UTC")
f.dateFormat = "yyyy-MM-dd"
print(f.date(from: "2024-02-30") as Any)
- nil
- 2024-03-01
- Crash
Predict first
What does this print for 30 December 2024?
let f = DateFormatter()
f.locale = Locale(identifier: "en_US_POSIX")
f.timeZone = TimeZone(identifier: "UTC")
f.dateFormat = "YYYY-MM-dd"
print(f.string(from: Date(timeIntervalSince1970: 1735516800)))
- 2024-12-30
- 2025-12-30
Mental model. A fixed-format formatter is a barcode scanner: it only works if the label is printed the way the scanner expects, whatever the shop’s local habits.
To parse or print a fixed format (an API timestamp) set three things: locale = en_US_POSIX, an explicit timeZone, and a dateFormat. Without the POSIX locale, the user’s settings can override your pattern. The famous failure is a 12/24-hour setting that makes h:mm a stop parsing, so it returns nil on some phones only.
Use yyyy for the calendar year, never YYYY (week-based year). A formatter is not lenient by default, so “2024-02-30” returns nil. Creating formatters is slow, so reuse one. For display that should follow the locale, build the format from a template with setLocalizedDateFormatFromTemplate instead of a literal pattern.
Non-lenient parsing rejects a date that does not exist, giving nil.
YYYY is the week-based year, and 30 December 2024 is in week 1 of 2025.
Common traps
YYYYinstead ofyyyy. Correct all year until the last days of December.- No
en_US_POSIX. Parsing works in your testing and fails for users with other 12/24-hour or calendar settings.
They might follow up with
- Is
DateFormatterthread-safe? Using one concurrently is supported, but mutating its properties from several threads is a race. - What about ISO 8601 with milliseconds?
ISO8601DateFormatterwith.withFractionalSeconds, or a customDate.ISO8601FormatStyle.
Related questions
- 2.2.7 FormatStyle or DateFormatter: which do you reach for?
- 2.2.3 How do Calendar and DateComponents work, and why can YYYY give the wrong year?
- 2.5.2 How are dates encoded and decoded in JSON, and why are they 31 years off?
← FormatStyle or DateFormatter: which do you reach for? How do you measure elapsed time, and how do you show a duration? →