Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS real monotonic clock other than mach_absolute_time()

Tags:

ios

My iOS app needs a custom clock that is synchronized with my server's clock all the time. All the synchronization logic is done.

My clock is based on mach_absolute_time() from which you can calculate the elapsed time since the device was booted. The problem is that when the device goes into sleep mode (by pressing the screen lock key and having no app running in background) the mach time ticking is paused. When the phone is awakened the mach time ticking resumes but it will not account for the time that the phone has been asleep.

This is how I calculate elapsed time since boot (but it won't account for the time the device is asleep)

- (long long) elapsedTimeMillis {
    uint64_t elapsedTimeNano = 0;

    mach_timebase_info_data_t timeBaseInfo;
    mach_timebase_info(&timeBaseInfo);

    elapsedTimeNano = mach_absolute_time() * timeBaseInfo.numer / timeBaseInfo.denom;
    return (long long)(elapsedTimeNano / 1000000);
}

And this has exactly the same results:

- (long long) elapsedTimeMillis {
    clock_serv_t cclock;
    mach_timespec_t mts;

    host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
    clock_get_time(cclock, &mts);
    mach_port_deallocate(mach_task_self(), cclock);

    return mts.tv_nsec / 1000000 + mts.tv_sec * 1000;
}

NSDate, CFAbsoluteTimeGetCurrent() or alike are not an option because they are affected by device time being sync'ed or manually changed by the user.

Is there ANY way to get time in iOS from a non-stop ticking clock that won't jump back or forth?

like image 440
fekke Avatar asked Dec 28 '13 17:12

fekke


1 Answers

This does the trick:

See: Getting iOS system uptime, that doesn't pause when asleep

- (time_t)uptime
{
    struct timeval boottime;
    int mib[2] = {CTL_KERN, KERN_BOOTTIME};
    size_t size = sizeof(boottime);
    time_t now;
    time_t uptime = -1;
    (void)time(&now);
    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0)
    {
        uptime = now - (boottime.tv_sec);
    }

    return uptime;
}

That returns SECONDS since last boot. Device sleeps won't affect it, neither will phone time syncs or phone time changes by the user. Unfortunately it doesn't return the milliseconds or nanoseconds.

like image 192
fekke Avatar answered Oct 06 '22 00:10

fekke