As said in one of the comments, POSIX's clock_gettime()
was implemented in iOS 10 and macOS 10.12. When used with the CLOCK_MONOTONIC
argument, it does seem to return the uptime value. However, this is not guaranteed by the documentation:
For this clock, the value returned by clock_gettime() represents the
amount of time (in seconds and nanoseconds) since an unspecified point
in the past (for example, system start-up time, or the Epoch). This
point does not change after system start-up time.
And an extract from the corresponding macOS man page:
CLOCK_MONOTONIC clock that increments monotonically, tracking the time since an arbitrary point, and will continue to increment while the system is asleep.
CLOCK_MONOTONIC_RAW clock that increments monotonically, tracking the time since an arbitrary point like CLOCK_MONOTONIC. However, this clock is unaffected by frequency or time adjustments. It should not be compared to other system time sources.
CLOCK_MONOTONIC_RAW_APPROX like CLOCK_MONOTONIC_RAW, but reads a value cached by the system at context
switch. This can be read faster, but at a loss of accuracy as it may return values that are milliseconds old.
CLOCK_UPTIME_RAW clock that increments monotonically, in the same manner as CLOCK_MONOTONIC_RAW, but that does not increment while the system is asleep. The returned value is identical to the result of mach_absolute_time() after the appropriate mach_timebase conversion is applied.
Note that CLOCK_MONOTONIC
returns with microsecond precision while CLOCK_MONOTONIC_RAW
with nanosecond precision.
Swift code:
func uptime() -> timespec {
var uptime = timespec()
if 0 != clock_gettime(CLOCK_MONOTONIC_RAW, &uptime) {
fatalError("Could not execute clock_gettime, errno: \(errno)")
}
return uptime
}
print(uptime()) // timespec(tv_sec: 636705, tv_nsec: 750700397)
For those still interested in getting the kernel's boot time in Swift:
func kernelBootTime() -> timeval {
var mib = [ CTL_KERN, KERN_BOOTTIME ]
var bootTime = timeval()
var bootTimeSize = MemoryLayout<timeval>.size
if 0 != sysctl(&mib, UInt32(mib.count), &bootTime, &bootTimeSize, nil, 0) {
fatalError("Could not get boot time, errno: \(errno)")
}
return bootTime
}
print(kernelBootTime()) // timeval(tv_sec: 1499259206, tv_usec: 122778)