Why does NSDateFormatter return null for 10/19/2014 in the Brazilian time zone?

NSString *dateString = @"19/10/2014"; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"dd/MM/yyyy"]; NSDate *myDate = [dateFormatter dateFromString:dateString]; 

Why is myDate null for this particular date (10/19/2014) ??

If I changed dateString to @"25/10/2014" , dateFormatter returned the date correctly ... What is wrong with my code?

* This code returns null when Brasilia, Brasilia is in my iPhone time zone. For example, when my time zone is Washington, DC, ECA, the code returns the correct date.

+12
ios objective-c nsdateformatter
Jun 06 '14 at 18:48
source share
3 answers

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 conclusion:

 2014-06-06 14:22:28.254 commandLine[31169:303] myDate = (null) 

Since you did not specify a time in the dateString , the system takes midnight. But midnight on this date does not exist in the Brazilian time zone .

Brazil changed from BRT (daylight saving time) to BRST (non-daylight time zone) on October 19, 2014 , skipping directly from the last moment "18/10/2014" to "19/10/2014 01:00:00".

Since "10/19/2014 00:00:00" does not exist, NSDateFormatter returns nil . I think this is bad behavior on the part of NSDateFormatter , but we have to deal with it. -[NSDateFormatter dateFromString:] ultimately calls CFDateFormatterGetAbsoluteTimeFromString , which uses the udat_parseCalendar function from International Components for Unicode Library (icu) to analyze the date.

You can work around the problem by forcing the parser to use midday instead of midnight as the default time. No time zones change in / out of daylight saving time at noon. Let's write a helper function that returns the 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 defaultDate date 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 is the conclusion:

 2014-06-06 14:52:31.939 commandLine[31982:303] myDate = 2014-10-19 14:00:00 +0000 
+21
Jun 06 '14 at 19:52
source share

Rob Mayoff provided an excellent explanation and solution to this problem. As Rob noted, midnight 10/19/2014 does not exist in the Brazilian time zone.

Another possible solution is to specify the date format "Soft". In this case, it will return the first valid date on the given day:

 NSString *dateString = @"19/10/2014"; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"America/Sao_Paulo"]; dateFormatter.dateFormat = @"dd/MM/yyyy"; dateFormatter.lenient = YES; NSDate *myDate = [dateFormatter dateFromString: dateString]; NSLog(@"myDate = %@", myDate); // myDate = 2014-10-19 03:00:00 +0000 

The result is "2014-10-19 03:00:00 UTC", which is "2014-10-19 01:00:00 BRST", that is, the first valid date on the day when daylight saving time starts.

+1
Oct 29 '16 at 15:39
source share

If your date that you want to format is a specific format that you want all devices in all regions to understand, you need to set the locale in your date formatting.

Without this, the default date format will correspond to the language. This will mean that the date format in Brazil is apparently not dd / MM / yyyy

You can force your date format to use a specific language like this:

 [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"]]; 

Hope this helps

W

-one
Jun 06 '14 at 19:47
source share



All Articles