Search code examples
iphoneiosnscalendar

calendric calculations in iOS broken before 1577... (julian -> gregorian)


The same code

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"d MMMM yyyy GG"];
//13th of December 1577
NSDate * aDate = [NSDate dateWithTimeIntervalSince1970:-12371067248]; 

NSString * formattedDate = [dateFormatter stringFromDate:aDate];

Mac OS X target shows formattedDate correctly

13th of December 1577

iOS 5.0 target shows

23rd of December 1577

as if the Julian -> Gregorian transition was bugged

Any ideas how to overcome that?


Solution

  • Try running this code on both Mac and iOS

    NSDateFormatter *localFormatter = [[NSDateFormatter alloc] init];
    localFormatter.timeStyle = NSDateFormatterNoStyle;
    localFormatter.dateStyle = NSDateFormatterMediumStyle;
    
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"g"];  // g = julian day number
    NSDate *d2299159 = [dateFormatter dateFromString:@"2299159"];
    NSDate *d2299160 = [dateFormatter dateFromString:@"2299160"];
    NSDate *d2299161 = [dateFormatter dateFromString:@"2299161"];
    NSDate *d2299162 = [dateFormatter dateFromString:@"2299162"];
    
    
    NSLog(@"Julian Day Number 2299159 = %@", [localFormatter stringFromDate:d2299159]);
    NSLog(@"Julian Day Number 2299160 = %@", [localFormatter stringFromDate:d2299160]);
    NSLog(@"Julian Day Number 2299161 = %@", [localFormatter stringFromDate:d2299161]);
    NSLog(@"Julian Day Number 2299162 = %@", [localFormatter stringFromDate:d2299162]);
    

    and you wil get these outputs (except the <-- notes):

    Mac

    Julian Day Number 2299159 = 1582-10-03   <-- Julian calendar
    Julian Day Number 2299160 = 1582-10-04   <-- Julian calendar
    Julian Day Number 2299161 = 1582-10-15   <-- Gregorian calendar
    Julian Day Number 2299162 = 1582-10-16   <-- Gregorian calendar
    

    iOS

    Julian Day Number 2299159 = 1582-10-13   <-- Proleptic Gregorian calendar
    Julian Day Number 2299160 = 1582-10-14   <-- Proleptic Gregorian calendar
    Julian Day Number 2299161 = 1582-10-15   <-- Gregorian calendar
    Julian Day Number 2299162 = 1582-10-16   <-- Gregorian calendar
    

    On the Mac NSDateFormatter switches to the Julian calendar (also called old style dates) for dates preceding Oct 15, 1582 which is the first day in the Gregorian calendar (that Apple works with. Some countries adopted on different dates). If you refer to Gregorian dates before this date, these dates are in the proleptic Gregorian calendar, meaning, dates before the Gregorian existed. And, as you can see from the second output NSDateFormatter on the iOS platform doesn't switch to the Julian calendar but stays in the proleptic Gregorian calendar. The difference in your output is exactly those 10 skipped days that were skipped in the transition from the Julian to the Gregorian.

    I can highly recommend this applet if you want to play around with different calendars to learn more about this stuff: http://www.cs.tau.ac.il/~nachum/calendar-book/Calendrica.html These guys also wrote a brilliant book on the subject.

    Also, Apple has a little section on Historical Dates in their documentation here: https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/DatesAndTimes/Articles/dtHist.html#//apple_ref/doc/uid/TP40010240-SW1 However, they do not mention NSDateFormatter implementation differences on different platforms!

    Working with calendars is from hell - good luck :-)