NSCalendarDate to be deprecated

  • My application needs to obtain the day of year for a given date. In the
    past, this was easily done with an NSCalendarDate.

    // NSCalendarDate faces deprecation
    int dayOfYearForDate1(NSDate *_date)
    {
        NSTimeZone *gmtTimeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
        NSCalendarDate *calendarDate = [_date dateWithCalendarFormat:nil
    timeZone:gmtTimeZone];
        int day = [calendarDate dayOfYear];
        return day;
    }

    NSCalendarDate faces deprecation: "Use of NSCalendarDate strongly
    discouraged. It is not deprecated yet, however it may be in the next major
    OS release after Mac OS X v10.5. For calendrical calculations, you should
    use suitable combinations of NSCalendar, NSDate, and NSDateComponents, as
    described in Calendars in Dates and Times Programming Topics for Cocoa."

    The above advice led to two alternate functions:

    int dayOfYearForDate2(NSDate *_date)
    {
        NSTimeZone *gmtTimeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
        NSCalendar *calendar = [[NSCalendar alloc]
    initWithCalendarIdentifier:NSGregorianCalendar];
        [calendar setTimeZone:gmtTimeZone];

        NSDateComponents *components = [calendar components:NSYearCalendarUnit
    fromDate:_date];
        int year = [components year];

        components = [[NSDateComponents alloc] init];
        [components setYear:year -1];
        [components setMonth:12];
        [components setDay:30];
        [components setHour:23];
        [components setMinute:59];
        [components setSecond:59];
        NSDate *lastYear1230 = [calendar dateFromComponents:components];
        [components release];

        components = [calendar components:NSDayCalendarUnit
    fromDate:lastYear1230 toDate:_date options:0];
        int day = [components day];
        [calendar release];
        return day;
    }

    int dayOfYearForDate3(NSDate *_date)
    {
        NSTimeZone *gmtTimeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
        NSCalendar *calendar = [[NSCalendar alloc]
    initWithCalendarIdentifier:NSGregorianCalendar];
        [calendar setTimeZone:gmtTimeZone];

        NSDateComponents *components = [calendar components:NSYearCalendarUnit
    fromDate:_date];
        int year = [components year];

        NSString *dateString = [NSString stringWithFormat:@"%d-12-30 23:59:59
    -0000", year - 1];
        NSDate *lastYear1230 = [NSDate dateWithString:dateString];

        components = [calendar components:NSDayCalendarUnit
    fromDate:lastYear1230 toDate:_date options:0];
        int day = [components day];
        [calendar release];
        return day;
    }

    To decide whether to use dayOfYearForDate2() or dayOfYearForDate3() in my
    application, I benchmarked all three functions:

    dayOfYearForDate1(): 8.76544 microseconds
    dayOfYearForDate2(): 46.9595 microseconds
    dayOfYearForDate3(): 74.5191 microseconds

    (The above times include 0.4 microseconds attributable to the testing
    overhead.)

    Since Apple's engineers would not throw away a perfectly good object without
    providing something better, I must be doing things the hard way. What is the
    easy way?

    Thanks in advance.

    ++ Tom

    Tom Bernard
    <tombernard...>
  • You could do this:

    int dayOfYearForDate(NSDate *_date)
    {
        NSCalendar *calendar = [[NSCalendar alloc]
    initWithCalendarIndentifier:NSGregorianCalendar]];
        int day = [calendar ordinalityOfUnit:NSDayCalendarUnit
    inUnit:NSYearCalendarUnit forDate:_date];
        return day;
    }

    I've never benchmarked this, but it's certainly a lot less code.

    Eliza

    On Aug 18, 2008, at 8:32 AM, Tom Bernard wrote:

    > My application needs to obtain the day of year for a given date. In
    > the
    > past, this was easily done with an NSCalendarDate.
    >
    > // NSCalendarDate faces deprecation
    > int dayOfYearForDate1(NSDate *_date)
    > {
    > NSTimeZone *gmtTimeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
    > NSCalendarDate *calendarDate = [_date dateWithCalendarFormat:nil
    > timeZone:gmtTimeZone];
    > int day = [calendarDate dayOfYear];
    > return day;
    > }
    >
    > NSCalendarDate faces deprecation: "Use of NSCalendarDate strongly
    > discouraged. It is not deprecated yet, however it may be in the next
    > major
    > OS release after Mac OS X v10.5. For calendrical calculations, you
    > should
    > use suitable combinations of NSCalendar, NSDate, and
    > NSDateComponents, as
    > described in Calendars in Dates and Times Programming Topics for
    > Cocoa."
    >
    > The above advice led to two alternate functions:
    >
    >
    > int dayOfYearForDate2(NSDate *_date)
    > {
    > NSTimeZone *gmtTimeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
    > NSCalendar *calendar = [[NSCalendar alloc]
    > initWithCalendarIdentifier:NSGregorianCalendar];
    > [calendar setTimeZone:gmtTimeZone];
    >
    > NSDateComponents *components = [calendar
    > components:NSYearCalendarUnit
    > fromDate:_date];
    > int year = [components year];
    >
    > components = [[NSDateComponents alloc] init];
    > [components setYear:year -1];
    > [components setMonth:12];
    > [components setDay:30];
    > [components setHour:23];
    > [components setMinute:59];
    > [components setSecond:59];
    > NSDate *lastYear1230 = [calendar dateFromComponents:components];
    > [components release];
    >
    > components = [calendar components:NSDayCalendarUnit
    > fromDate:lastYear1230 toDate:_date options:0];
    > int day = [components day];
    > [calendar release];
    > return day;
    > }
    >
    >
    > int dayOfYearForDate3(NSDate *_date)
    > {
    > NSTimeZone *gmtTimeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
    > NSCalendar *calendar = [[NSCalendar alloc]
    > initWithCalendarIdentifier:NSGregorianCalendar];
    > [calendar setTimeZone:gmtTimeZone];
    >
    > NSDateComponents *components = [calendar
    > components:NSYearCalendarUnit
    > fromDate:_date];
    > int year = [components year];
    >
    > NSString *dateString = [NSString stringWithFormat:@"%d-12-30
    > 23:59:59
    > -0000", year - 1];
    > NSDate *lastYear1230 = [NSDate dateWithString:dateString];
    >
    > components = [calendar components:NSDayCalendarUnit
    > fromDate:lastYear1230 toDate:_date options:0];
    > int day = [components day];
    > [calendar release];
    > return day;
    > }
    >
    >
    >
    >
    > To decide whether to use dayOfYearForDate2() or dayOfYearForDate3()
    > in my
    > application, I benchmarked all three functions:
    >
    > dayOfYearForDate1(): 8.76544 microseconds
    > dayOfYearForDate2(): 46.9595 microseconds
    > dayOfYearForDate3(): 74.5191 microseconds
    >
    > (The above times include 0.4 microseconds attributable to the testing
    > overhead.)
    >
    > Since Apple's engineers would not throw away a perfectly good object
    > without
    > providing something better, I must be doing things the hard way.
    > What is the
    > easy way?
    >
    > Thanks in advance.
    >
    > ++ Tom
    >
    > Tom Bernard
    > <tombernard...>
  • I wish NSCalendarDate could be fixed instead of discarded. I find it a
    convenient class, and it is heavily used in the standard sync schemas.
    If it must go, I hope somebody comes up with an open source
    replacement for it. :)

    Dave
  • As written, 70 microseconds. When I set the calendar's time zone to GMT, the
    time drops to 43 microseconds. Since my app will only work with dates in
    GMT, this is a plus. Even so, 40 microseconds is far slower than the 7 - 8
    microseconds offered by -[NSCalendarDate dayOfYear]. Unless someone has
    another offering, I plan to file a bug report on this issue. This
    calculation is part of an animation loop, so the performance hit is
    important.

    Btw, my two offerings return an incorrect 367 for the date 2008-12-31
    23:59:59 +0000; 2008 being a leap year, the correct return is 366. Your
    offering and NSCalendarDate get it right.

    int dayOfYearForDate4(NSDate *_date)
    {
        NSTimeZone *gmtTimeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
          NSCalendar *calendar = [[NSCalendar alloc]
    initWithCalendarIdentifier:NSGregorianCalendar];
        [calendar setTimeZone:gmtTimeZone];

        int day = [calendar ordinalityOfUnit:NSDayCalendarUnit
    inUnit:NSYearCalendarUnit forDate:_date];
        return day;
    }

    on 8/18/08 7:34 AM, Eliza Block at <eliza.block...> wrote:

    > You could do this:
    >
    > int dayOfYearForDate(NSDate *_date)
    > {
    > NSCalendar *calendar = [[NSCalendar alloc]
    > initWithCalendarIndentifier:NSGregorianCalendar]];
    > int day = [calendar ordinalityOfUnit:NSDayCalendarUnit
    > inUnit:NSYearCalendarUnit forDate:_date];
    > return day;
    > }
    >
    > I've never benchmarked this, but it's certainly a lot less code.
  • I too find NSCalendarDate tremendously useful. The fact that it is
    used (not to say necessary) in Sync Services let me believe it won't
    be deprecated. I hope Apple won't ask 3rd party developer dto rewrite
    their code using Sync Services ...

    Aurélien,
    Objective Decision Team

    On 18 août 08, at 17:22, David Riggle wrote:

    > I wish NSCalendarDate could be fixed instead of discarded. I find it
    > a convenient class, and it is heavily used in the standard sync
    > schemas. If it must go, I hope somebody comes up with an open source
    > replacement for it. :)
    >
    > Dave
  • > As written, 70 microseconds. When I set the calendar's time zone to
    > GMT, the
    > time drops to 43 microseconds. Since my app will only work with
    > dates in
    > GMT, this is a plus. Even so, 40 microseconds is far slower than the
    > 7 - 8
    > microseconds offered by -[NSCalendarDate dayOfYear]. Unless someone
    > has
    > another offering, I plan to file a bug report on this issue. This
    > calculation is part of an animation loop, so the performance hit is
    > important.
    Sorry to jump in late, but I am just now getting around to reading
    about 5 days worth of email. Did you try caching the NSCalendar
    creation call? I believe we had a similar performance issue with
    CFCalendar (which no doubt shares its implementation with NSCalendar),
    and I found out with Shark and fs_usage that each CFCalendarCreate
    call results in many (very large) region data files being read into
    memory. <sarcasm>Turns out reading several megabytes from the
    filesystem is expensive</sarcasm>, so caching the CFCalendarCreate
    resulted in a big performance gain. Not sure if NSCalendar implements
    any caching on its own, but you might give it a shot.

    Ryan
  • Please do jump in late, especially with a 20 microsecond suggestion. Full
    details are at

    http://bersearch.com/PrivateTechSupport/NSCalendarBenchmark/NSCalendarBench
    mark1.0.zip

    I have filed a bug report titled

    Planned NSCalendarDate deprecation yields slower performance
    Bug ID# 6179834

    Thanks again to you and to Eliza Block for your suggestions.

    ++ Tom

    Tom Bernard
    <tombernard...>

    on 8/22/08 12:00 AM, Ryan McGann at <rmcgann...> wrote:

    >> As written, 70 microseconds. When I set the calendar's time zone to
    >> GMT, the
    >> time drops to 43 microseconds. Since my app will only work with
    >> dates in
    >> GMT, this is a plus. Even so, 40 microseconds is far slower than the
    >> 7 - 8
    >> microseconds offered by -[NSCalendarDate dayOfYear]. Unless someone
    >> has
    >> another offering, I plan to file a bug report on this issue. This
    >> calculation is part of an animation loop, so the performance hit is
    >> important.
    > Sorry to jump in late, but I am just now getting around to reading
    > about 5 days worth of email. Did you try caching the NSCalendar
    > creation call? I believe we had a similar performance issue with
    > CFCalendar (which no doubt shares its implementation with NSCalendar),
    > and I found out with Shark and fs_usage that each CFCalendarCreate
    > call results in many (very large) region data files being read into
    > memory. <sarcasm>Turns out reading several megabytes from the
    > filesystem is expensive</sarcasm>, so caching the CFCalendarCreate
    > resulted in a big performance gain. Not sure if NSCalendar implements
    > any caching on its own, but you might give it a shot.
previous month august 2008 next month
MTWTFSS
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Go to today