Question

Given the following code:

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
NSLog(@"Date from String: %@", [formatter dateFromString:@"2013-09-08T00:36:40"]);

The log produces: Date from String: (null)

For other strings from the same source it works, but i'm failing to see why in this case fails.

Could someone enlighten me?

Update: I have updated the code as follows, still fails:

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
[formatter setLocale:locale];

NSDate *date = nil;
NSError *error = nil;

[formatter getObjectValue:&date
                         forString:@"2013-09-08T00:36:40"
                             range:NULL
                             error:&error];

NSLog(@"Date from String: %@", date);
NSLog(@"Error: %@", error);

The output: 2014-03-31 15:27:01.697 Untitled[30859:507] Date from String: (null) 2014-03-31 15:27:01.710 Untitled[30859:507] Error: Error Domain=NSCocoaErrorDomain Code=2048 "The value “2013-09-08T00:36:40” is invalid." UserInfo=0x7f89d8e04cd0 {NSInvalidValue=2013-09-08T00:36:40}

Update 2: After some playing around I found out my timezone is the reason it fails (I don't understand why, but it only fails under my timezone)

The following code fails:

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
[formatter setLocale:locale];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:@"America/Santiago"]];

NSDate *date = nil;
NSError *error = nil;

[formatter getObjectValue:&date
                         forString:@"2013-09-08T00:36:40"
                             range:NULL
                             error:&error];

NSLog(@"Date from String: %@", date);
NSLog(@"Error: %@", error);

Any suggestions to work around it?

Was it helpful?

Solution

The error was caused because that date doesn't exist under the Chilean zone (due to DST change).

While NSDateFormatter is correct to return nil because it doesn't exist. It's not feasible to tell the user "The file was created in a time your timezone never experienced".

The solution (that applies to any other zone with DST) is to set a timezone just like the current one without DST.

NSString *dateString = ...; //Assume it is defined
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
[formatter setLocale:locale];
//Date formatting might fail because of Daylight Saving Timezones and the like. So, we force the timezone to one just like it where the date always exist.
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:[[NSTimeZone localTimeZone] secondsFromGMT]]];

NSDate *date = nil;
NSError *error = nil;

[formatter getObjectValue:&date
                         forString:dateString
                             range:NULL
                             error:&error];

Again, this is not technically correct to do, but it is OK to do for display purposes.

OTHER TIPS

According to http://www.timeanddate.com/time/zone/chile/santiago, the Daylight Savings Time for the time zone "America/Santiago" started in the year 2013 on Sun, 8 Sep, 00:00, which means that the clocks were adjusted one hour forward to Sun, 8 Sep, 01:00.

Therefore the time "00:36:40" does not exist on that day. That is the reason that the conversion fails.

A possible solution could be to fill a NSDateComponents with the given components and then call dateFromComponents:

NSCalendar *cal = [NSCalendar currentCalendar];
[cal setTimeZone:[NSTimeZone timeZoneWithName:@"America/Santiago"]];
NSDateComponents *comp = [[NSDateComponents alloc] init];
comp.year = 2013;
comp.month = 9;
comp.day = 8;
comp.hour = 0;
comp.minute = 36;
comp.second = 40;
NSDate *d = [cal dateFromComponents:comp];
NSLog(@"Date from components: %@", d);        //  2013-09-08 04:36:40 +0000
NSString *s = [formatter stringFromDate:d];
NSLog(@"String from date: %@", s);            //  2013-09-08T01:36:40

This gives the same date for all "valid" date strings, and also a sensible result for the "invalid" date string during the daylight saving time transition.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top