1

I need to measure elapsed time, in order to know when a certain period of time has been exceeded.

I used to use Ticks() and Microseconds() for this, but both functions are now deprecated.

CFAbsoluteTimeGetCurrent is not the correct way to use because it may run backwards, as explained in the docs:

Repeated calls to this function do not guarantee monotonically increasing results. The system time may decrease due to synchronization with external time references or due to an explicit user change of the clock.

What else is there that's not deprecated and fairly future-proof?

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149
  • 1
    `mach_absolute_time`? Fascinating discussion here: http://stackoverflow.com/questions/23378063/how-can-i-use-mach-absolute-time-without-overflowing (Off-topic: Hi, Thomas!) – matt May 12 '15 at 19:07
  • (Hi MattN!) Yes, thanks for the pointer about mach_absolute_time - I had found Q&A 1398 in the mean time but was not aware of the overflows. I'd expect there are other ways as well, though, maybe using timers (though I don't know if they're acting correctly if the clock changes back). – Thomas Tempelmann May 12 '15 at 19:21
  • 1
    One of the other deprecated timing functions, `UpTime`, is declared in DriverServices.h. Comments in that header say "Use CFAbsoluteTime or mach time routines instead". – JWWalker May 12 '15 at 20:33

2 Answers2

2

One way, as explained in Q&A 1398, is to use mach_absolute_time as follows:

    static mach_timebase_info_data_t sTimebaseInfo;
    mach_timebase_info(&sTimebaseInfo); // Determines the time scale

    uint64_t t1 = mach_absolute_time();
    ...
    uint64_t t2 = mach_absolute_time();
    uint64_t elapsedNano = (t2-t1) * sTimebaseInfo.numer / sTimebaseInfo.denom;

This may not be fool-proof either, though. The values could overflow in some cases, as pointed out in this answer.

Community
  • 1
  • 1
Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149
  • 1
    I've had good results with `mach_absolute_time`. A while back I made a little Cocoa class wrapper around it, as described [here](http://zpasternack.org/high-resolution-timing-in-cocoa-revisited/). – zpasternack May 12 '15 at 20:33
1

Use NSTimeInterval:

Used to specify a time interval, in seconds.

Example:

- (void)loop {

    NSDate *startTime = [NSDate date];

    sleep(90); // sleep for 90 seconds

    [self elapsedTime:startTime];
}

- (void)elapsedTime:(NSDate *)startTime {

NSTimeInterval elapsedTime = fabs([startTime timeIntervalSinceNow]);

int intSeconds = (int) elapsedTime;
int intMinutes = intSeconds / 60;
intSeconds = intSeconds % 60;

NSLog(@"Elapsed Time: %d minute(s) %d seconds", intMinutes, intSeconds);

}

Result:

Elapsed Time: 1 minute(s) 29 seconds

It's unclear what type of precision you are looking for, although NSTimeInterval can accomodate fractions of a second (eg. tenths, hundredths, thousandths, etc.)

l'L'l
  • 44,951
  • 10
  • 95
  • 146
  • NSDate is, like CFAbsoluteTimeGetCurrent, able to run backwards, though, isn't it? I mean, a user could simply change his clock manually, and you already have it going back. Or isn't `timeIntervalSinceNow` prone to this? – Thomas Tempelmann May 13 '15 at 07:28
  • 1
    Yes, unfortunately almost any date/time method is prone to that. If you're worried about the possibility of it happening you could do a check within a specified interval of the elapsed time to determine if the current time is less than the start time — and if it is then invalidate it. – l'L'l May 13 '15 at 18:46