I believe I might have found a bug in NSDateFormatter
, and I am not sure if this is localized to having a Brazil time zone specified in System Preferences.
A full project is here: http://www.idanfe.com/dl/nsDateFormatterPuzzle.zip
The relevant excerpts of the code is shown below:
NSArray *unformattedDatesArray = [[NSArray alloc] initWithObjects:@"2011-09-18",
@"2011-10-16",@"2011-11-13",@"2011-12-11",@"2012-01-08",@"2012-02-05", nil];
NSString *resultedString = @"";
int ii = 0;
NSUInteger items = [unformattedDatesArray count];
for (ii=0; ii<items; ii++) {
NSLog(@"original item # %d = %@",ii,[unformattedDatesArray objectAtIndex:ii]);
resultedString = [resultedString stringByAppendingString:@"original item # "];
resultedString = [resultedString stringByAppendingString:[NSString stringWithFormat: @"%d = ",ii]];
resultedString = [resultedString stringByAppendingString:[unformattedDatesArray objectAtIndex:ii]];
resultedString = [resultedString stringByAppendingString:[NSString stringWithFormat:@"\n"]];
}
NSDateFormatter *originalFormat = [[NSDateFormatter alloc] init];
[originalFormat setDateFormat:@"yyyy-MM-dd"]; // hh:mm:ss
NSDateFormatter *newFormat = [[NSDateFormatter alloc] init];
[newFormat setDateFormat:@"dd/MM/yyyy"]; // hh:mm:ss
NSString *formattedDate;
for (ii=0; ii<items; ii++) {
formattedDate = [newFormat stringFromDate:[originalFormat
dateFromString:[unformattedDatesArray objectAtIndex:ii]]];
NSLog(@"formatted item # %d = %@",ii,formattedDate);
resultedString = [resultedString stringByAppendingString:@"formatted item # "];
resultedString = [resultedString stringByAppendingString:[NSString stringWithFormat: @"%d = ",ii]];
resultedString = [resultedString stringByAppendingString:(formattedDate == nil ? @"ERROR" : formattedDate)];
resultedString = [resultedString stringByAppendingString:[NSString stringWithFormat:@"\n"]];
}
[resultingStringTextView insertText:resultedString];
Basically, I'm starting with an array of 5 NSString
s which represent dates. I'm creating 2 NSDateFormatter
s: originalFormat
is used to convert the original string representation of the date into an actual NSDate
; newFormat
is used to create a new desired string representation of the NSDate
generated with the originalFormat
date formatter.
This is my resulting log:
2012-08-26 nsDateFormatterPuzzle[3261:303] original item # 0 = 2011-09-18
2012-08-26 nsDateFormatterPuzzle[3261:303] original item # 1 = 2011-10-16
2012-08-26 nsDateFormatterPuzzle[3261:303] original item # 2 = 2011-11-13
2012-08-26 nsDateFormatterPuzzle[3261:303] original item # 3 = 2011-12-11
2012-08-26 nsDateFormatterPuzzle[3261:303] original item # 4 = 2012-01-08
2012-08-26 nsDateFormatterPuzzle[3261:303] original item # 5 = 2012-02-05
2012-08-26 nsDateFormatterPuzzle[3261:303] formatted item # 0 = 18/09/2011
2012-08-26 nsDateFormatterPuzzle[3261:303] formatted item # 1 = (null)
2012-08-26 nsDateFormatterPuzzle[3261:303] formatted item # 2 = 13/11/2011
2012-08-26 nsDateFormatterPuzzle[3261:303] formatted item # 3 = 11/12/2011
2012-08-26 nsDateFormatterPuzzle[3261:303] formatted item # 4 = 08/01/2012
2012-08-26 nsDateFormatterPuzzle[3261:303] formatted item # 5 = 05/02/2012
Note that if you go to System Preferences --> Date and Time --> Time Zone
and change your Time Zone to Rio de Janeiro, you will have the same results.
================================ TRYING to Workaround ===================================
I am trying to get a workaround this bug meanwhile Apple does not fix it.
I have two problems, one is to render a PDF file from this date, and I think I have solved this by:
if (formated_issue_date == NULL) {
formated_issue_date = [BHDateFormatter bhDateFormat:data_emissao];
}
Using this handler:
+(NSString*)bhDateFormat:(NSString *)inputedDate{
NSString *formattedDate = @"";
NSRange range82 = NSMakeRange (8, 2);
NSRange range52 = NSMakeRange (5, 2);
NSRange range04 = NSMakeRange (0, 4);
NSString *firstBlock = [inputedDate substringWithRange:range82];
NSString *secondBlock = [inputedDate substringWithRange:range52];
NSString *thirdBlock = [inputedDate substringWithRange:range04];
formattedDate = [formattedDate stringByAppendingString:firstBlock];
formattedDate = [formattedDate stringByAppendingString:@"/"];
formattedDate = [formattedDate stringByAppendingString:secondBlock];
formattedDate = [formattedDate stringByAppendingString:@"/"];
formattedDate = [formattedDate stringByAppendingString:thirdBlock];
return formattedDate;
}
The second problem is that the invoice date is loaded into a a table view that contains a date formatter, and changing this would cause the sorting of the table to be lost.
Using the same principle as my handler, and insisting on passing the 16/10/2011 date causes errors on the table view, like: -[__NSCFString timeIntervalSinceReferenceDate]: unrecognized selector sent to instance 0x40265f3a0
This is the best code I found so far:
if (formatterDate == NULL) {
NSLog (@"outprintString '%@' = NULL", dateString);
NSString *newDate = [BHDateFormatter bhDateFormat:dateString];
if ([newDate isEqualToString:@"16/10/2011"]) {
formatterDate = [inputFormatter dateFromString:@"2011-10-17"];
NSLog(@"formatterDate = %@", formatterDate);
NSAlert *alert = [[[NSAlert alloc]init] autorelease];
[alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"Mountain Lion Bug: I have found a date \"16/10/2011\" in your invoice # %@ issued by %@, I must rename the date in your table view to \"17/10/2011\", the date on the rendered invoice file will be display correctly. I apologize for this, but it is an operating system level bug that has to be fixed by Apple.","A comment here"),invoiceNumber, emitente]];
[alert runModal];
}
}
Could you please comment?
Thanks!
It's not a bug. October 16 is the day that Brazil went onto southern-hemisphere daylight saving time that year, and your proposed time (assumed to be midnight, since you don't give an explicit time) is during the missing hour. It is a non-existent time.
I believe that you're right -- that is a bug, and you should report it. Interestingly, if you set the timezone to Nuuk-Greenland, which is in the same timezone as Rio, it works properly. Also, "2011-10-15" and "2011-10-17" work ok with the Rio time zone, but not "2011-10-16" which is really strange.
This is the simplified the code that I used to test this:
Added Information:
To find the source of this problem, I looped through all the dates in 2011 with the following code:
When you look at the date strings, you find that there are 2 february 19th's and no October 16th, which is why you get null for that date (although if you log the date objects themselves, you get all the dates correctly).