Gup3rSuR4c
Gup3rSuR4c

Reputation: 9480

How to find if an NSDate is within a specified range?

So, I'm having a difficult time (no pun intended) finding if an NSDate is within a specific range. Consider this: a scheduled visit between 5:00 PM and 6:00 PM. I want to find if the scheduled visit is within +/- 15 minutes of the current time. Thus my safe range is 4:45 PM to 6:15 PM. How can I find out if the scheduled visit is in or out of the range? Here's the code I've got so far, which doesn't work at all...

- (BOOL)isInScheduledRange {
//    NSLog(@"Start: %f", [self.start timeIntervalSinceNow]);
//    NSLog(@"End: %f", [self.end timeIntervalSinceNow]);
//    
//    if (([self.start timeIntervalSinceNow] >= -900) && ([self.end timeIntervalSinceNow] <= 3600)) {
//        NSLog(@"In Range");
//        
//        return YES;
//    }
//    
    NSDate *now = [[NSDate alloc] init];

//    if ((([self.start timeIntervalSinceDate:now] >= -900) && ([self.start timeIntervalSinceDate:now] <= 900)) && (([self.end timeIntervalSinceDate:now] <= -900) && ([self.end timeIntervalSinceDate:now] >= 900))) {
//        NSLog(@"In Range");
//    }

    NSLog(@"%@; %@; %@", now, self.start, self.end);
//    NSLog(@"%@; %@", [self.start timeIntervalSinceDate:now], [self.end timeIntervalSinceDate:now]);

    if ((([self.start timeIntervalSinceDate:now] >= -900) && ([self.start timeIntervalSinceDate:now] <= 0)) && (([self.end timeIntervalSinceDate:now] >= 0) && ([self.end timeIntervalSinceDate:now] <= 900))) {
        NSLog(@"In Range");
    }

    return NO;

    [now release];
}

I'd appreciate some help. I'm having difficulties with this time calculation.

On a separate note, I hate dealing with time no matter what platform I'm working with...

Upvotes: 6

Views: 1720

Answers (4)

Thomson Comer
Thomson Comer

Reputation: 3919

This is a distance problem - you want to know if the current time is within 900 seconds of the target time. Compute distance problems by taking the absolute value of the difference between the two points. By taking the absolute value of the difference, the order of the two samples doesn't matter.

/** 
 * @brief Return YES if the current time is within 900 seconds of the meeting time (NSDate* time).
 */
-(BOOL)currentTimeIsWithin900SecondsOf:(NSDate*)time
{
    NSDate* now = [NSDate date];
    return fabs( [now timeIntervalSinceReferenceDate] - [time timeIntervalSinceReferenceDate] ) < 900;
}

Upvotes: 2

Mark Kuric
Mark Kuric

Reputation: 156

Here's some verbose (and silly) code that explains my approach to this problem

NSTimeInterval secondsBeforeStart = [self.start timeIntervalSinceNow];
if ( secondsBeforeStart > (15 * 60))
{
    // The result for '[self.start timeIntervalSinceNow]' is positive as long
    //  as 'self.start' remains in the future. We're not in range until there
    //  are 900 seconds to go or less.
    NSLog( @"Still time to chill.");

    // More than fifteen minutes to go so return NO.
    return NO;
}
else
{
    NSLog( @"OMG did I miss it!!!");
    NSTimeInterval secondsBeforeEnd = [self.end timeIntervalSinceNow];
    if ( secondsBeforeEnd < -( 15 * 60))
    {
        // The result for '[self.end timeIntervalSinceNow]' is negative when
        //  'self.end' is in the past. 
        // It's been more than 900 seconds since the end of the appointment
        //  so we've missed it.
        NSLog( @"Ahhhhh!!!");

        // More than 900 seconds past the end of the event so return NO.
        return NO;
    }
    else
    {
        // We are somewhere between 900 seconds before the start and
        //  900 seconds before the end so we are golden.
        NSLog( @"Whew, we made it.");
        return YES;
    }
}

The way I would have coded it would have been

BOOL inRange = NO;  // Assume we are not in the proper time range.

if ( [self.start timeIntervalSinceNow] <= ( 15 * 60))
{
    // 'Now' is at least 900 seconds before the start time but could be later.
    if ( [self.end timeIntervalSinceNow] >= -( 15 * 60))
    {
        // 'Now' is not yet 900 seconds past the end time.
        inRange = YES
    }
}

return inRange;

Note: I haven't actually compiled this but I'm pretty sure the logic is correct.

Finally, you did notice that your last two lines

    return NO;

    [now release];
}

would have created a memory leak. (Release and then return ;^))

Upvotes: 3

ughoavgfhw
ughoavgfhw

Reputation: 39905

You want to check if the start time is less than 900 seconds after the current time, and the end time is less than 900 seconds before the current time. timeIntervalSinceDate: returns a positive number if the object it is called on is after the argument, you need to check for start <= 900 and end >= −900. Also, you could simplify your code by using timeIntervalSinceNow instead of manually getting the current date and passing it to timeIntervalSinceDate:. Finally, if you can assume (or previously ensured) that the start is before the end, then you don't need the two middle tests, as they will both have to be true for both of the others to be true.

if([self.start timeIntervalSinceNow] <= 900 && [self.end timeIntervalSinceNow] >= −900) {
    NSLog(@"In range")
}

Upvotes: 6

Moshe
Moshe

Reputation: 58077

You need to create three NSDates. Then convert NSDates to time intervals using intervalSinceReferenceDate and compare those. You manually set up NSDates by using NSDateComponents.

Upvotes: 0

Related Questions