NSDateFormatter Puzzle! Is this is new Mountain Lion Bug?

Dear friends,

Would you please run this project in your Mountain Lion Mac and post your results here?

Please inform your localization.

I believe it might be a bug, and I am not sure if this localized to Brazil date format.

Download project from:

http://www.idanfe.com/dl/nsDateFormatterPuzzle.zip

This is my resulting log:

2012-08-26 01:32:17.875 nsDateFormatterPuzzle[3261:303] original item # 0 = 2011-09-18
2012-08-26 01:32:17.876 nsDateFormatterPuzzle[3261:303] original item # 1 = 2011-10-16
2012-08-26 01:32:17.876 nsDateFormatterPuzzle[3261:303] original item # 2 = 2011-11-13
2012-08-26 01:32:17.877 nsDateFormatterPuzzle[3261:303] original item # 3 = 2011-12-11
2012-08-26 01:32:17.877 nsDateFormatterPuzzle[3261:303] original item # 4 = 2012-01-08
2012-08-26 01:32:17.877 nsDateFormatterPuzzle[3261:303] original item # 5 = 2012-02-05
2012-08-26 01:32:17.883 nsDateFormatterPuzzle[3261:303] formatted item # 0 = 18/09/2011
2012-08-26 01:32:17.884 nsDateFormatterPuzzle[3261:303] formatted item # 1 = (null)
2012-08-26 01:32:17.885 nsDateFormatterPuzzle[3261:303] formatted item # 2 = 13/11/2011
2012-08-26 01:32:17.886 nsDateFormatterPuzzle[3261:303] formatted item # 3 = 11/12/2011
2012-08-26 01:32:17.887 nsDateFormatterPuzzle[3261:303] formatted item # 4 = 08/01/2012
2012-08-26 01:32:17.887 nsDateFormatterPuzzle[3261:303] formatted item # 5 = 05/02/2012

This is my resulting window:

http://www.idanfe.com/dl/screenshot.png

Thanks for your help.

I have more info about this:

Go to System Preferences → Date and Time → Time Zone

Change your Time Zone to Rio de Janeiro.

Run my app!

FWIW, I get the same result here with Rio time. Very puzzling – dateFromString is returning nil for that date.

I tried this with various time zones:

    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:0];
    NSDateFormatter *originalFormat = [[NSDateFormatter alloc] init];
    [originalFormat setDateFormat:@"yyyy-MM-dd"]; 
    NSDateFormatter *newFormat = [[NSDateFormatter alloc] init];
    [newFormat setDateFormat:@"dd/MM/yyyy"];
    for (int ii=0; ii<10000; ii++) {
        date = [date dateByAddingTimeInterval:24*60*60];
        NSString *string = [originalFormat stringFromDate:date];
        NSDate *newDate = [originalFormat dateFromString:string];
        if (!newDate) {
            NSLog(@"failed: %@",string);
        }
    }

They’re definitely out to get you in Rio :frowning: A couple of places to the south only failed for a couple of dates, but I had no errors with the dozen or so others I tried.

So yes, it looks like a bug to me. And a most odd one…

Shane,

I posted this code and results over at SO to look into this problem further:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

    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
    
    NSDate *start = [originalFormat dateFromString:@"2011-01-01"];
    NSDate *newDate;
    for (int i=0; i<365; i++) {
        newDate = [start dateByAddingTimeInterval:86400 * i];
        NSString *formattedDate = [newFormat stringFromDate:newDate];
        NSLog(@"date is: %@  formatted date string is: %@",newDate,formattedDate);
    }
}

If you check out the logs you get from this (using the Rio timezone) you’ll see that the date objects are all correct, but the string for February 19th is repeated once, and the string for October 16th is missing. These 2 dates correspond to the change to and from daylight savings time in 2011. I’m not sure how the stringFromDate method works, but a poster at SO thought there was a problem with something called a zoneinfo file.

Ric

I had one of my customers complaining, and I checked, it was true!

iCal had 2 days “February 19th”, and I believe some how, this day had 25 hours, due to summer → winter time change, and so one day overlapped the other.

The two problems might be related.

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!

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.

Add another column to your data, containing the actual dates – it doesn’t have to appear. Then for the column of strings you want to sort, set the sort key to whatever you named the new column.

Use:

NSString *formattedDate = [NSString stringWithFormat:@"%@/%@/%@", firstBlock, secondBlock, thirdBlock];

In fact, if what you are trying to do is convert from one format to another, using string manipulation like this might be quicker anyway.

Dear Ric,

Do you think this bug can be related NOT to Apple’s Operating System Code, but somehow, related to how the Brazilian Government publishes its anual calendar?

I have no idea how time zone works, but this bug is certainly related to the brazilian daylight saving program. I guess that brazilian government is responsible for publishing its calendar to some TIME ZONE related international database.

The ICU collates the information, I think. At any rate, Apple are the people to report it to. Meanwhile you can work around it if you know of another zone with the same time offset and daylight savings days. You might want to have the code check the running OS first, and then use something like:

 if ([[[NSTimeZone localTimeZone] name] isEqualToString:@"America/Sao_Paulo"]) {
   [NSTimeZone setDefaultTimeZone:[NSTimeZone timeZoneWithName:@"<new zone with same time>"]];
 }

That should change it just for your app. Just make sure you run one of the previous scripts to check your new choice.

Dear Shane and Ric,

I was able to work around the bug with your help.

Thank you for your kind help,