Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a better way to find midnight tomorrow?

Is there a better way to do this?

-(NSDate *)getMidnightTommorow {
    NSCalendarDate *now = [NSCalendarDate date];
    NSCalendarDate *tomorrow = [now dateByAddingYears:0 months:0 days:1 hours:0 minutes:0 seconds:0];
    return [NSCalendarDate dateWithYear:[tomorrow yearOfCommonEra]
                                  month:[tomorrow monthOfYear]
                                    day:[tomorrow dayOfMonth]
                                   hour:0
                                 minute:0
                                 second:0
                               timeZone:[tomorrow timeZone]];
}

Note that I always want the next midnight, even if it happens to be midnight when I make that call, however if it happens to be 23:59:59, I of course want the midnight that is coming in one second.

The natural language functions seem flaky, and I'm not sure what Cocoa would do if I pass 32 in the "day" field. (If that'd work I could drop the [now dateByAddingYears:...] call)

like image 522
Dre Avatar asked Oct 08 '08 05:10

Dre


2 Answers

From the documentation:

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.

Following that advice:

NSDate *today = [NSDate date];

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDateComponents *components = [[NSDateComponents alloc] init];
components.day = 1;
NSDate *tomorrow = [gregorian dateByAddingComponents:components toDate:today options:0];
[components release];

NSUInteger unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
components = [gregorian components:unitFlags fromDate:tomorrow];
components.hour = 0;
components.minute = 0;

NSDate *tomorrowMidnight = [gregorian dateFromComponents:components];

[gregorian release];
[components release];

(I'm not sure offhand if this is the most efficient implementation, but it should serve as a pointer in the right direction.)

Note: In theory you can reduce the amount of code here by allowing a date components object with values greater than the range of normal values for the component (e.g. simply adding 1 to the day component, which might result in its having a value of 32). However, although dateFromComponents: may tolerate out-of-bounds values, it's not guaranteed to. You're strongly encouraged not to rely on it.

like image 159
mmalc Avatar answered Sep 20 '22 20:09

mmalc


Nope - it'll be the same way you use to find midnight today.

like image 32
loudej Avatar answered Sep 20 '22 20:09

loudej