Search code examples
cocoa-touchiosnsdatenscalendarnsdatecomponents

Date since 1600 to NSDate?


I have a date that's stored as a number of days since January 1, 1600 that I need to deal with. This is a legacy date format that I need to read many, many times in my application.

Previously, I'd been creating a calendar, empty date components and root date like this:

self.gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar
                    ] autorelease];
id rootComponents = [[[NSDateComponents alloc] init] autorelease];
[rootComponents setYear: 1600];
[rootComponents setMonth: 1];
[rootComponents setDay: 1];
self.rootDate = [gregorian dateFromComponents: rootComponents];
self.offset = [[[NSDateComponents alloc] init] autorelease];

Then, to convert the integer later to a date, I use this:

[offset setDay: theLegacyDate];
id eventDate = [gregorian dateByAddingComponents: offset
                                          toDate: rootDate
                                         options: 0];

(I never change any values in offset anywhere else.)

The problem is I'm getting a different time for rootDate on iOS vs. Mac OS X. On Mac OS X, I'm getting midnight. On iOS, I'm getting 8:12:28. (So far, it seems to be consistent about this.) When I add my number of days later, the weird time stays.

OS       | legacyDate | rootDate                  | eventDate
======== | ========== | ==========================|==========================
Mac OS X | 143671     | 1600-01-01 00:00:00 -0800 | 1993-05-11 00:00:00 -0700
iOS      | 143671     | 1600-01-01 08:12:28 +0000 | 1993-05-11 07:12:28 +0000

In the previous release of my product, I didn't care about the time; now I do. Why the weird time on iOS, and what should I do about it? (I'm assuming the hour difference is DST.)

I've tried setting the hour, minute and second of rootComponents to 0. This has no impact. If I set them to something other than 0, it adds them to 8:12:28. I've been wondering if this has something to do with leap seconds or other cumulative clock changes.

Or is this entirely the wrong approach to use on iOS?


Solution

  • It looks like the right answer is to make things simpler. Instead of making a rootDate, I just build the date from components every time. This should be no slower, and is still keeps the code really close to the idea.

    Initial setup:

    self.gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar
                        ] autorelease];
    self.components = [[[NSDateComponents alloc] init] autorelease];
    [components setYear: 1600];
    [components setMonth: 1];
    

    (Obviously, properties and ivars are adjusted.)

    Later, to actually convert a legacy date to a NSDate:

    [components setDay: 1 + theLegacyDate];
    id eventDate = [gregorian dateFromComponents: components];
    

    This has these advantages for me:

    1. It users fewer ivars.
    2. It's less code.
    3. It always returns midnight on that day, regardless of whether DST is in effect.