1st april dates of 80s failed to parse in iOS 10.0
This problem occurs if daylight saving time starts exactly on
midnight, as it was the case in Moscow in the years 1981–1984 (see for example Clock Changes in Moscow, Russia (Moskva)).
This was also observed in
- Why does NSDateFormatter return nil date for these 4 time zones? and
- Why NSDateFormatter is returning null for a 19/10/2014 in a Brazilian time zone?
For example, at midnight of April 1st 1984, the clocks were adjusted one hour forward, which means that the date "1984-04-01 00:00"
does not exist in that timezone:
let dFmt = DateFormatter()
dFmt.dateFormat = "yyyy-MM-dd"
dFmt.timeZone = TimeZone(identifier: "Europe/Moscow")
print(dFmt.date(from: "1984-04-01")) // nil
As a solution, you can tell the date formatter to be "lenient":
dFmt.isLenient = true
and then it will return the first valid date on that day:
dFmt.isLenient = true
if let date = dFmt.date(from: "1984-04-01") {
dFmt.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(dFmt.string(from: date))
}
// 1984-04-01 01:00:00
A different solution
was given by rob mayoff, which is to make the date formatter use noon instead of midnight as the
default date. Here is a translation of rob's code from Objective-C to Swift:
let noon = DateComponents(calendar: dFmt.calendar, timeZone: dFmt.timeZone,
year: 2001, month: 1, day: 1, hour: 12, minute: 0, second: 0)
dFmt.defaultDate = noon.date
if let date = dFmt.date(from: "1984-04-01") {
dFmt.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(dFmt.string(from: date))
}
// 1984-04-01 12:00:00
Swift Dateformatting fails for just a specific day
I suppose you are living in Brasil.
On October 16, 2016 the daylight saving time changes and there is no 0:00.
getting nil date from string using formatter
Are you living in a country where daylight saving time changes on 2017-03-22
at midnight?
If yes this could be the reason because the date does not exist.
Swift 5 - Unexplainable DateFormatter Crash
In your locale the daylight saving time changes at 2 am on March 14, 2021, therefore the particular date doesn't exist.
Why NSDateFormatter is returning null for a 19/10/2014 in a Brazilian time zone?
We can reproduce your problem by explicitly setting the time zone to “Brazil/East”:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *dateString = @"19/10/2014";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"Brazil/East"];
[dateFormatter setDateFormat:@"dd/MM/yyyy"];
NSDate *myDate = [dateFormatter dateFromString:dateString];
NSLog(@"myDate = %@", myDate);
}
return 0;
}
Here's the output:
2014-06-06 14:22:28.254 commandLine[31169:303] myDate = (null)
Since you didn't give a time in your dateString
, the system assumes midnight. But midnight on that date doesn't exist in the Brazilian time zone.
Brazil changes from BRT (daylight-saving time zone) to BRST (non-daylight-saving time zone) on October 19, 2014, skipping directly from the last moment of “18/10/2014” to “19/10/2014 01:00:00”.
Since “19/10/2014 00:00:00” doesn't exist, NSDateFormatter
returns nil
. I think this is bad behavior on the part of NSDateFormatter
, but we have to deal with it. -[NSDateFormatter dateFromString:]
eventually calls CFDateFormatterGetAbsoluteTimeFromString
, which uses the udat_parseCalendar
function from the International Components for Unicode (icu) library to parse the date.
You can work around the problem by making the parser use noon instead of midnight as the default time. No time zones change to/from daylight saving time at noon. Let's write a helper function that returns noon of some arbitrary date in a given time zone:
static NSDate *someDateWithNoonWithTimeZone(NSTimeZone *timeZone) {
NSDateComponents *components = [[NSDateComponents alloc] init];
components.timeZone = timeZone;
components.era = 1;
components.year = 2001;
components.month = 1;
components.day = 1;
components.hour = 12;
components.minute = 0;
components.second = 0;
return [[NSCalendar autoupdatingCurrentCalendar] dateFromComponents:components];
}
Then we set the date formatter's defaultDate
to this noon date:
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *dateString = @"19/10/2014";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"Brazil/East"];
dateFormatter.dateFormat = @"dd/MM/yyyy";
dateFormatter.defaultDate = someDateWithNoonWithTimeZone(dateFormatter.timeZone);
NSDate *myDate = [dateFormatter dateFromString:dateString];
NSLog(@"myDate = %@", myDate);
}
return 0;
}
And here's the output:
2014-06-06 14:52:31.939 commandLine[31982:303] myDate = 2014-10-19 14:00:00 +0000
Related Topics
Building iOS Applications Using Xcodebuild Without Codesign
iPhone - When to Calculate Heightforrowatindexpath for a Tableview When Each Cell Height Is Dynamic
Get Current iPhone Device Timezone Date and Time from Utc-5 Timezone Date and Time iPhone App
After Switching to Xcode 7, App Size Grew from 9 Mb to 60 Mb, Is There a Fix
Refresh Uipageviewcontroller - Reorder Pages and Add New Pages
iOS Video Compression Swift iOS 8 Corrupt Video File
Checking a Null Value in Objective-C That Has Been Returned from a JSON String
How Is the Relation Between Uiview's Clipstobounds and Calayer's Maskstobounds
Uibutton Doesn't Listen to Content Mode Setting
Uicollectionview Adding Uicollectioncell
Upload Image to the PHP Server from iOS
What Does Main.Sync in Global().Async Mean
Using Autolayout in a Tableheaderview
Creating iPhone Pop-Up Menu Similar to Mail App Menu
How to Use Navigation Controller Inside of Uitabbarcontroller with Storyboard on Swift
How to Prevent from Scrolling Uitableview Up When Nsfetchedresultscontroller Add New Record