1St April Dates of 80S Failed to Parse in iOS 10.0

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



Leave a reply



Submit