In our app there is the issue with creating a date from string but is only reproducible with a very specific combination. Unfortunately, there is no way of getting it from the user that experienced the issue, so I decided to just go for it and try every possible combination:
import Foundation
var dateOnlyDateFormatter: (String, String) -> DateFormatter = { timeZoneS, localeS in
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
formatter.timeZone = TimeZone(identifier: timeZoneS)
formatter.locale = Locale(identifier: localeS)
return formatter
}
let date = "2022-05-27"
let time = "06:15"
for timeZone in TimeZone.knownTimeZoneIdentifiers {
for locale in Locale.availableIdentifiers {
let dateFormatter = dateOnlyDateFormatter(timeZone, locale)
let printDate = dateFormatter.date(from: date)
if printDate == nil {
print("TimeZone: (timeZone), Locale: (locale)")
}
}
}
The result:
TimeZone: America/Asuncion, Locale: ar_SA
TimeZone: America/Asuncion, Locale: en_SA
I am not too sure what is the best way to handle this issue. Obviously our BE could return date using one specific Locale, like en_US_POSIX
, but I have very little control over that, being a part of a much bigger older system. Has anybody experienced an issue like that?
2
Answers
So if you use ‘time’ like this, there will be no nil values:
If you read the "Working With Fixed Format Date Representations" section of the
DateFormatter
docs, you’ll find:You should probably just follow the advice here… But here’s possibly why SA and the Paraguay timezone produces nil.
Further down that section, there is a link to a technical Q&A where this is explained in more detail. The part that is most related to your problem is:
In the locale SA, the numbers of your date string seem to be interpreted using the Islamic Calendar. Take a look at today’s date when formatted with en_SA and America/New_York.
Also take a look at the non-nil dates that is parsed by en_SA and America/New_York
Notice that 10-05 is the first Sunday of the year 2583 (See this calendar). If Paraguay still uses the same DST rules as it does now in 2583, then it would mean that there is a DST gap transition at 2583-10-05 00:00:00, starting the DST period. The hour starting from 00:00:00 would be skipped, so 00:00:00 would not exist.
When parsing a date only,
DateFormatter
would try to set the time components to be 00:00:00 in the timezone of the formatter, but 00:00:00 does not exist, so the parsing fails.In any case, just set
locale
to posix andtimeZone
to UTC when you have setdateFormat
.