10

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?

fekke
  • 351
  • 3
  • 10
  • ios is basically a unix system. It **SHOULD** have an uptime counter somewhere, which is elapsed time since boot. That would basically just be "current time - time at boot". may not have the accuracy you'd need, but it should always be available. – Marc B Dec 28 '13 at 17:28
  • @MarcB you're right it SHOULD. But at least in iPhone 4s with iOS7, what it looks like an uptime counter (that is SYSTEM_CLOCK or mach_absulte_time()) unfortunatly DOES pause ticking when device goes into sleep mode. So if you use that to calculate date/time at boot it will be missing all the seconds it's been asleep since boot. – fekke Dec 28 '13 at 17:43
  • that'd be rather stupid of iOS. My android phone keeps a realtime `uptime` count that reflects elapsed time since boot, regardless of how much of that time was spent asleep/locked. – Marc B Dec 28 '13 at 17:45
  • @Zaph your solution will not work for me because that time is based on the phone clock or "wall clock". And yes, the user can change that clock's time (not only timezone). Thanks anyway. – fekke Dec 28 '13 at 18:12
  • @MarcB finally you lead me to the answer... I've been googling "ios boot time" but googling "ios uptime" did the trick ;) (see my answer) – fekke Dec 28 '13 at 18:14

2 Answers2

4

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.

Community
  • 1
  • 1
fekke
  • 351
  • 3
  • 10
1

There is now a mach_continuous_time function that includes time while the system is asleep:

Returns current value of a clock that increments monotonically in tick units (starting at an arbitrary point), including while the system is asleep.

Note that it returns the time in ticks, which is inconvenient. You can instead use clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW) to get nanoseconds.

Here's a complete example in Swift:

import Foundation

let elapsed_time_nanos = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)

(I don't think it was available back when this question was asked. I'm not sure with which iOS version it was introduced exactly, but it's there on at least iOS 15.)

robinst
  • 30,027
  • 10
  • 102
  • 108
  • According to 'https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+/refs/heads/lts_2018_06_20/absl/time/internal/get_current_time_ios.inc' it's available from IOS 10.2 – Sachin Khokhar Mar 24 '23 at 13:46