iOS 11.2.6中DateFormatter.date在巴西利亚夏令时区域返回nil
DateFormatter.date(from:) Returns Nil in Brazilian Summer Time (BRST) for "11/20" Great question — this is a tricky edge case tied to how DateFormatter handles missing date components and Brazil's unique daylight saving time (DST) history. Let’s break down what’s happening and how to fix it:
Root Cause
When you use a date format like "MM/yy", DateFormatter doesn’t automatically fill in missing day/time components with safe defaults (like the 1st of the month at midnight). Instead, it uses the current day of the month and current time from the device’s system clock to complete the date.
In BRST, the 2020 DST transition created a "missing hour" on October 18th: clocks jumped forward from 00:00 to 01:00, so any time between 00:00-01:00 that day never existed. If your code runs during that exact window (or if you test with a system clock set to it), DateFormatter will try to create a date like 2020-11-18 00:XX:XX (using the current day and time). Since this time doesn’t exist in BRST, the formatter returns nil.
Even outside that hour, inconsistencies in how DateFormatter resolves missing components across timezones can trigger unexpected nil returns in BRST due to its unique DST history.
How to Fix It
You need to take control of missing date components instead of relying on DateFormatter’s default behavior. Here are two reliable solutions:
Solution 1: Explicitly Set a Default Date
Configure the formatter to use a fixed default date for missing components (like the 1st of the month at midnight). This guarantees the parsed date is always valid:
let dateFormatter = DateFormatter() dateFormatter.dateFormat = "MM/yy" // Set a default date to fill missing day/time components dateFormatter.defaultDate = Calendar.current.date(from: DateComponents(year: 2000, month: 1, day: 1, hour: 0, minute: 0, second: 0)) if let date = dateFormatter.date(from: "11/20") { print("got the date: \(date)") } else { print("failed getting the date") }
Solution 2: Parse Components Manually
For full control, split the string into individual components and build the date yourself using Calendar:
let dateString = "11/20" let components = dateString.split(separator: "/") guard components.count == 2, let month = Int(components[0]), let yearSuffix = Int(components[1]) else { print("failed getting the date") return } // Assume 21st century for two-digit year let year = 2000 + yearSuffix let dateComponents = DateComponents(year: year, month: month, day: 1) if let date = Calendar.current.date(from: dateComponents) { print("got the date: \(date)") } else { print("failed getting the date") }
Bonus: Lock Timezone/Locale (Optional)
For consistent parsing across all regions, explicitly set the formatter’s timezone and locale to avoid system-dependent variations:
dateFormatter.timeZone = TimeZone(identifier: "UTC") dateFormatter.locale = Locale(identifier: "en_US_POSIX")
内容的提问来源于stack exchange,提问作者Adam Johns

