5

Is there a way to get system uptime in iOS (using Swift)? What I need is to measure time without having to worry about the user changing the time. In Android there's a elapsedCurrentTimeMillis() that returns the number of milliseconds since boot, but now I need something like that for iOS. There's an accepted answer here Getting iOS system uptime, that doesn't pause when asleep but that's for Objective C and I need it for Swift and I don't know how to convert it.

Community
  • 1
  • 1
TimSim
  • 3,936
  • 7
  • 46
  • 83
  • What about just `NSProcessInfo.processInfo().systemUptime`? – JAL Mar 24 '16 at 16:06
  • 1
    That doesn't take into account sleep time. I need a way to reliably measure how much time has passed, even if the app is shut down in the meantime and even if the user changes the time. – TimSim Mar 24 '16 at 16:11

4 Answers4

16

As you ask for a pure-Swift solution, I converted the ObjC code from the answer you mentioned Getting iOS system uptime, that doesn't pause when asleep.

func uptime() -> time_t {
    var boottime = timeval()
    var mib: [Int32] = [CTL_KERN, KERN_BOOTTIME]
    var size = strideof(timeval)

    var now = time_t()
    var uptime: time_t = -1

    time(&now)
    if (sysctl(&mib, 2, &boottime, &size, nil, 0) != -1 && boottime.tv_sec != 0) {
        uptime = now - boottime.tv_sec
    }
    return uptime
}

// print(uptime())

To make it a bit prettier, we can use sysctlbyname instead of sysctl:

// var mib: [Int32] = [CTL_KERN, KERN_BOOTTIME]
sysctlbyname("kern.boottime", &boottime, &size, nil, 0)
Community
  • 1
  • 1
Donghua Li
  • 451
  • 2
  • 9
  • 2
    @JAL I debugged and figured out the different behaviour of sizeof between ObjC and Swift. It works now! – Donghua Li Mar 24 '16 at 16:20
  • Yup, this works, shows the same value as Objective-C code version! And I can see I'm going to have a hard time programming... – TimSim Mar 24 '16 at 16:30
  • 2
    i get a `Use of unresolved identifier 'strideof'` error in swift 5. looks like the syntax changed but i am not sure what to – Anushk May 23 '20 at 08:21
  • 2
    @Anushk replace `strideof(timeval)` with `MemoryLayout.stride` – Sam Nov 07 '20 at 23:42
6

This is a solution in Swift 4.

 var boottime = timeval()
 var size = MemoryLayout<timeval>.stride
 sysctlbyname("kern.boottime", &boottime, &size, nil, 0) 
Anthony Kong
  • 37,791
  • 46
  • 172
  • 304
6

Updated for Swift 5 and straight from ADF post here:

func bootTime() -> Date? {  
    var tv = timeval()  
    var tvSize = MemoryLayout<timeval>.size  
    let err = sysctlbyname("kern.boottime", &tv, &tvSize, nil, 0);  
    guard err == 0, tvSize == MemoryLayout<timeval>.size else {  
        return nil  
    }  
    return Date(timeIntervalSince1970: Double(tv.tv_sec) + Double(tv.tv_usec) / 1_000_000.0)  
}

"Be aware that this time will change if the system clock changes, that is, the value is the boot time relative to the current system clock."

Richard Poutier
  • 207
  • 2
  • 10
  • What's the point of boot time that depends on the system clock changes? Did they change this behavior or what? – TimSim Jul 29 '20 at 16:48
2

You can call ObjC code from Swift:

print(SystemUtil().uptime());

Write a ObjC class like the accepted answer you mentioned: Getting iOS system uptime, that doesn't pause when asleep.

SystemUtil.h for interface:

#import <Foundation/Foundation.h>

@interface SystemUtil : NSObject

- (time_t)uptime;

@end

SystemUtil.m for implementation:

#import "SystemUtil.h"
#include <sys/sysctl.h>

@implementation SystemUtil

- (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;
}

@end

And don't forget to include a <Project>-Bridge-Header.h with the following content so that you can use the ObjC class from Swift (<Project> is your project name):

#import "SystemUtil.h"
Community
  • 1
  • 1
Donghua Li
  • 451
  • 2
  • 9
  • The OP is asking for a native Swift solution. – JAL Mar 24 '16 at 15:40
  • This works. I think. It's showing plausible non-zero uptime. For anyone as dumb as me, all you need to do is create the .h and .m files in Xcode (File->New->File...->iOS->Source) and put in them what @donghua-li wrote, and Bridge-Header.h will be automatically created (so just add the #import) – TimSim Mar 24 '16 at 16:24
  • @TimSim I've worked out a [pure-Swift solution](http://stackoverflow.com/a/36204651/4912403). – Donghua Li Mar 24 '16 at 16:31