0

In the iPhone docset for NSDate, in the discussion area they discuss -dateWithNaturalLanguageString:locale:, however they don't document the method elsewhere on the page.

I've used the method before for iPhone and it worked just fine, although I got warnings. Now that I'm building with -Werror (which I should have been doing all along ^_^) I've run into a warning with this.

How would I replace the following lines of code?

NSDate *today = [NSDate dateWithNaturalLanguageString:@"today at 23:59:59"];
NSDate *tomorrow = [NSDate dateWithNaturalLanguageString:@"tomorrow at 23:59:59"];
jbrennan
  • 11,943
  • 14
  • 73
  • 115

2 Answers2

2

One way to do this is with NSCalendar and NSDateComponents.

To get today at 23:59:59:

NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];

NSDateComponents *comps = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit 
                                      fromDate:date];

[comps setHour:23];
[comps setMinute:59];
[comps setSecond:59];

NSDate *today = [calendar dateFromComponents:comps];

To get tomorrow at 23:59:59:

NSDate *now = [NSDate dateWithTimeIntervalSinceNow:24 * 60 * 60]; // 24h from now
NSCalendar *calendar = [NSCalendar currentCalendar];

NSDateComponents *comps = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit 
                                      fromDate:date];

[comps setHour:23];
[comps setMinute:59];
[comps setSecond:59];

NSDate *tomorrow = [calendar dateFromComponents:comps];
iKenndac
  • 18,730
  • 3
  • 35
  • 51
  • Bingo. Thanks to everyone for their help. – jbrennan Aug 27 '09 at 22:28
  • I will certainly not be forgetting NSDateComponents any time soon! – jbrennan Aug 27 '09 at 22:30
  • This answer is the opposite of the original poster's intent (and my interest), I think? My understanding was that he wanted to start with a natural language date "tomorrow at 23:59:59" and get a resulting NSDate. – Greg Combs Aug 15 '13 at 16:03
1

Let's assume:

static const unsigned long seconds_per_day = 60 * 60 * 24;

You can get now and now+24 hours with:

NSDate* today = [NSDate date]; // set for today
NSDate* tomorrow = [today addTimeInterval:seconds_per_day];

In order to get midnight for the given day, it's important to remember that NSDate* is toll-free bridged to CFDateRef, which provides some additional APIs you'll want to use. In particular, you can convert an NSDate to a CFAbsoluteTime with CFDateGetAbsoluteTime:

CFAbsoluteTime abstime = CFDateGetAbsoluteTime(reinterpret_cast<CFDateRef>(myNSDate));
long long      inttime = static_cast<long long>(abstime);

inttime = (inttime / seconds_per_day) * seconds_per_day; // clips the time to midnight

NSDate* myNSDateAtMidnight = reinterpret_cast<NSDate*>(CFDateCreate(NULL,
                                                       static_cast<CFAbsoluteTime>(inttime)));

... which you can wrap into a function to round both today and tomorrow to midnight.

fbrereto
  • 35,429
  • 19
  • 126
  • 178
  • Where is CFAbsoluteTime declared? I've imported ` but still no dice. Also, what is myUint64Type? What should I be using for that? If it matters, I'm writing an NSDate category, although I don't think it matters. – jbrennan Aug 27 '09 at 03:31
  • Ah, there's a typo in your code, `CFAbosoluteTime` ;) Anyway I've got the code running now, but it's still not quite right. The time for today and tomorrow is still off... – jbrennan Aug 27 '09 at 18:42
  • What do the dates print when you say `NSLog(@"%@", myNSDate)`? – fbrereto Aug 27 '09 at 18:56
  • Also I changed `myUint64Type` to be `long long` – fbrereto Aug 27 '09 at 18:57
  • I've pasted my code here http://paste.lisp.org/display/86144 Thanks for your help so far :) We're getting there. – jbrennan Aug 27 '09 at 19:51
  • I think it's actually correct -- you have to take into account the UTC offset, which is -3 hours; so you add 3 hours to 21:00:00 and you get 24:00:00, which is midnight, today. – fbrereto Aug 27 '09 at 20:18
  • Hmmm, well 21:00 is off by 3 hours, but 16:41 is not. I'm trying to get "the end of today", instead of "the start of today". What a peculiar problem... – jbrennan Aug 27 '09 at 20:24
  • Hmm... I guess then what you'll want to do is add the amount of UTC time to compute midnight for your particular time zone, then add to that value seconds_per_day - 1. That should give you the last second for today in your specific time zone. – fbrereto Aug 27 '09 at 20:29