Parsing fixed-format date strings is tricky. For an explanation as to why, see QA1480
NSDateFormatter and Internet Dates. However, there’s an extra wrinkle when you try to parse fixed-format date strings that don’t include a time. Consider this code:
Code Block func startOfDateInSaoPaulo(_ dateStr: String) -> Date? { |
let df = DateFormatter() |
df.locale = Locale(identifier: "en_US_POSIX") |
df.timeZone = TimeZone(identifier: "America/Sao_Paulo")! |
df.dateFormat = "yyyyMMdd" |
return df.date(from: dateStr) |
} |
The goal here is to parse a string of the form
yyyyMMdd and return the start of that day in São Paulo, Brazil. And the code seems to work. For example:
Code Block print(startOfDateInSaoPaulo("20200722")?.description ?? "nil") |
// -> 2020-07-22 03:00:00 +0000 |
It even handles daylight saving time changes. São Paulo set the clocks forward on 4 Nov 2018, and you can see this change when you map 3 Nov and 5 Nov:
Code Block print(startOfDateInSaoPaulo("20181103")?.description ?? "nil") |
// -> 2018-11-03 03:00:00 +0000 |
print(startOfDateInSaoPaulo("20181105")?.description ?? "nil") |
// -> 2018-11-05 02:00:00 +0000 |
Note Time zones in Brazil are very exciting. If you’re curious, read
Time in Brazil and
Daylight saving time in Brazil. Also, for those Northern hemisphere folks out there, keep in mind that São Paulo is in the southern hemisphere and thus the daylight saving “spring forward” happens in the second half of the year.
However, consider this:
Code Block print(startOfDateInSaoPaulo("20181104")?.description ?? "nil") |
// -> nil |
Whoah!?! This is failing because, internally, the date formatter maps the date string to a set of date components (
DateComponents). The year, month, and day come from the date string, but the hour, minute, and second default to 0. In Brazil, daylight saving time starts at midnight, and thus the date components
year: 2018, month: 11, day: 4, hour: 0, minute: 0, second: 0 don’t exist in the São Paulo time zone. When the date formatter runs these components through the calendar, it returns
nil.
Note Making daylight saving time changes at midnight is weird but Brazil is not the only country that does this.