Reputation: 18558
I probably didn't word that title clearly enough, but if the user specifies a time of 2:30pm and it's currently 2:00pm, then I need an NSDate object that represents the current day with a time of 2:30pm. If the user specifies a time of 2:30pm and it's currently 3:00pm, then I need an NSDate object that represents tomorrow with a time of 2:30pm. Similar to how an alarm clock would work.
I already wrote this code, but it's embarrassingly long and it feels really kludgy and I feel like it should be more simple, but I'm new to iOS development and this specific API.
Thanks so much in advance for your help!
Upvotes: 3
Views: 1255
Reputation: 527
If you get userDate from the user, and nowDate = [NSDate date]
, then
NSComparisonResult diff = [userDate compare: nowDate];
If the diff is NSOrderedDescending
, then userDate is later than nowDate, and you set the alarm for today. If it's NSOrderedAscending
, then you set the alarm for tomorrow. You can test for NSOrderedSame
, but it will never be.
You'd like to avoid having to determine what day it is, so it seems to me that adding an NSTimeInterval
of the difference plus 24 * 60 * 60 (if the alarm is tomorrow) or just the difference (if the alarm is today) would suffice.
I don't know why everyone is trying to make alarm clocks. It can't be done, as best I can tell.
Upvotes: 0
Reputation: 243146
Assuming that the user is using a UIDatePicker
to select the date, here's what I would do:
NSDate * selectedDate = ...; //2:30pm
NSDate * selectedComponents = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:selectedDate];
NSDate * now = [NSDate date];
NSDate * nowComponents = [[NSCalendar currentCalendar] components:NSUIntegerMax fromDate:now];
[nowComponents setHour:[selectedComponents hour]];
[nowComponents setMinute:[selectedComponents minute]];
NSDate * targetDate = [[NSCalendar currentCalendar] dateFromComponents:nowComponents];
if ([[now laterDate:targetDate] isEqual:now]) {
//in a comparison between now and the target date, the target date has already passed
[nowComponents setDay:[nowComponents day]+1];
targetDate = [[NSCalendar currentCalendar] dateFromComponents:nowComponents];
}
//target date is now at the appropriate 2:30pm
Side note: since the NSCalendarUnit
is a bitfield typedef for NSUInteger
, I pass in NSUIntegerMax
to retrieve all possible calendar units. That way I don't have to have a massive bitwise OR statement.
Upvotes: 1
Reputation: 15625
If you add a time interval that messes up around the daylight savings dates, I believe. Adding seconds for one day will then end up a day after but an hour earlier or later. I'm pretty sure I ran into this before, but you can test that easily, I guess.
Another way would be to use NSDateComponents:
// using while will be inefficient when the targetDate is more than a few days in the past
while ([targetDate compare:[NSDate date]] == NSOrderedAscending) {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger units = NSYearCalendarUnit |
NSMonthCalendarUnit |
NSDayCalendarUnit |
NSHourCalendarUnit |
NSMinuteCalendarUnit |
NSSecondCalendarUnit;
NSDateComponents *comps = [calendar components:units fromDate:targetDate];
[comps setDay:[comps day] + 1]; // if day is 32 for instance, it'll automatically roll over to the next month
NSDate *targetDate = [calendar dateFromComponents:comps];
}
The above is by no means an ideal solution (it'll leak targetDate if you retained it, for instance), but is mainly meant to show you how to add 1 day to a NSDate using NSDateComponents.
Upvotes: 1
Reputation: 17898
Do you already have an NSDate representing the date/time the user picked? If so, it's a pretty simple matter to compare it to now (via earlierDate:
or laterDate:
), and create a new one a day later (via dateWithTimeInterval:sinceDate:
or initWithTimeInterval:sinceDate:
).
Something like this:
// Assume dateTarget is an NSDate representing the date/time the user picked.
// Is it earlier than now?
if( [dateTarget earlierDate:[NSDate date]] == dateTarget ) {
// dateTarget is earlier than now.
// Add 1 day to it.
NSDate* newDate = [[NSDate alloc]initWithTimeInterval:60*60*24 sinceDate:dateTarget];
[dateTarget release];
dateTarget = newDate;
}
// dateTarget is now either the original time, or if that time passed, the same time tomorrow.
NSLog( @"dateTarget = %@", dateTarget );
Upvotes: 1