Does NSDateFormatter have a propensity for unexpectedly returning nil? I wouldn't think it did. I am hoping that I have overlooked some miniscule detail which for whatever reason I cannot see.
I have some data describing the sun and moon. It's listed below. I also have a loop which iterates over this data once it is loaded from its plist into a dictionary. Finally I have a class which processes dates for me using NSDateFormatter as a singleton. This process has worked pretty well and these methods have been interacting and producing correct dates for a month or two, but today it crashed. All of the strings being created and passed through this simple process are correctly converted into dates except the last one which is nil. Here's what happened:
This is the data in the property list.
<key>2014-3-7</key>
<dict>
<key>moonrise</key>
<string>10:51 am</string>
<key>moonset</key>
<string>0:03 am</string>
<key>phase</key>
<string>Waxing Crescent</string>
<key>sunrise</key>
<string>6:39 am</string>
<key>sunset</key>
<string>6:21 pm</string>
</dict>
<key>2014-3-8</key>
<dict>
<key>moonrise</key>
<string>11:39 am</string>
<key>moonset</key>
<string>0:56 am</string>
<key>phase</key>
<string>First Quarter</string>
<key>sunrise</key>
<string>6:38 am</string>
<key>sunset</key>
<string>6:21 pm</string>
</dict>
<key>2014-3-9</key>
<dict>
<key>moonrise</key>
<string>1:28 pm</string>
<key>moonset</key>
<string>2:45 am</string>
<key>phase</key>
<string></string>
<key>sunrise</key>
<string>7:37 am</string>
<key>sunset</key>
<string>7:22 pm</string>
</dict>
This data is processed through a loop creating dates from date strings starting with yesterday and ending tomorrow, so in this case it starts on the 7th or march and ends on the 9th and we are working with the values in each plist item for the given date as a dictionary called iDay.
NSString *eventString;
NSDate *moonrise;
NSDate *moonset;
NSString *dateFormatString = @"yyyy-MM-dd h:mm a";
if ([iDay objectForKey:@"moonrise"] != nil) {
eventString = [NSString stringWithFormat:@"%@ %@", dateString, [iDay objectForKey:@"moonrise"]];
moonrise = [self.dateTime makeDateFromString:eventString
format:dateFormatString];
}
if ([iDay objectForKey:@"moonset"] != nil) {
eventString = [NSString stringWithFormat:@"%@ %@",dateString, [iDay objectForKey:@"moonset"]];
moonset = [self.dateTime makeDateFromString:eventString
format:dateFormatString];
}
The strings being passed to [self.dateTime makeDateFromString] by these statements look like this:
2014-3-7 10:51 am
2014-3-7 0:03 am
2014-3-8 11:39 am
2014-3-8 0:56 am
2014-3-9 1:28 pm
2014-3-9 2:45 am
Okay, good. Now the dateTime singleton:
+(ADateTimeClass *) sharedDateTime {
@synchronized(self)
{
if (sharedInstance == NULL)
sharedInstance = [[self alloc] init];
}
return sharedInstance;
}
-(id) init{
self = [super init];
if(self){
self.dateFormat = [NSDateFormatter new];
self.dateFormat.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
}
return self;
}
... and the method where it all goes horribly wrong. All of the strings passed to this method get returned correctly as dates except the last one, and I've checked, the nil is coming from "[dateFormat dateFromString:dateString]" right here where dateString is one of the six I listed above.
-(NSDate*) makeDateFromString:(NSString *)dateString format:(NSString *)format{
[dateFormat setDateFormat:format];
NSDate* aDate = [dateFormat dateFromString:dateString];
return aDate;
}
And the results:
Printing description of moonrise: 2014-03-07 14:51:00 +0000
Printing description of moonset: 2014-03-07 04:03:00 +0000
Printing description of moonrise: 2014-03-08 15:39:00 +0000
Printing description of moonset: 2014-03-08 04:56:00 +0000
Printing description of moonrise: 2014-03-09 16:28:00 +0000
Printing description of moonset: <nil> <------------ !!!!!! Huh???
It's a simple problem actually depending on where you live. At least in the USA, any time from March 9 2014 between 2am and 2:59am won't exist due to daylight saving time change. Therefore any such date is invalid.