47

iOSでシステムの稼働時間を常に増加させる絶対的な方法を探しています。

デバイスが最後に再起動されてからの時刻が返され、システム日付の変更による影響を受けないはずです。

私が見つけることができるすべての方法は、デバイスがスリープしているときに一時停止するか(、、CACurrentMediaTime[NSProcessInfo systemUptime]mach_absolute_timeまたはシステムの日付が変更されると変更されます(sysctl/KERN_BOOTTIME)。

何か案は?

4

6 に答える 6

54

私はそれを解決したと思います。

time()デバイスがスリープしている間もインクリメントを続けますが、もちろんオペレーティングシステムまたはユーザーが操作できます。ただし、システムクロックが変更されると、カーネルの起動時間(システムが最後に起動したときのタイムスタンプ)も変更されるため、これらの値は両方とも固定されていなくても、それらの間のオフセットは固定されます。

#include <sys/sysctl.h>

- (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;
}
于 2012-09-19T07:41:02.900 に答える
26

コメントの1つで述べたように、POSIX clock_gettime()はiOS10とmacOS10.12に実装されました。引数とともに使用するとCLOCK_MONOTONIC、稼働時間の値を返すように見えます。ただし、これはドキュメントによって保証されていません。

このクロックの場合、clock_gettime()によって返される値は、過去の不特定の時点(たとえば、システムの起動時間やエポック)からの時間(秒とナノ秒)を表します。このポイントは、システムの起動時間後も変わりません。

そして、対応するmacOSのマニュアルページからの抜粋:

CLOCK_MONOTONICクロックは単調に増加し、任意のポイントからの時間を追跡し、システムがスリープしている間も増加し続けます。

CLOCK_MONOTONIC_RAWクロックは単調に増加し、CLOCK_MONOTONICのような任意のポイントからの時間を追跡します。ただし、このクロックは周波数や時間の調整の影響を受けません。他のシステムタイムソースと比較しないでください。

CLOCK_MONOTONIC_RAW_APPROXはCLOCK_MONOTONIC_RAWに似ていますが、コンテキストスイッチでシステムによってキャッシュされた値を読み取ります。これはより速く読み取ることができますが、ミリ秒前の値を返す可能性があるため、精度が低下します。

CLOCK_MONOTONIC_RAWと同じように単調に増加するが、システムがスリープしている間は増加しないCLOCK_UPTIME_RAWクロック。戻り値は、適切なmach_timebase変換が適用された後のmach_absolute_time()の結果と同じです。

ナノ秒の精度であるのCLOCK_MONOTONICに対し、マイクロ秒の精度で戻ることに注意してください。CLOCK_MONOTONIC_RAW

スウィフトコード:

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)

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)
于 2017-07-12T21:47:27.403 に答える
15

リストされているすべての例に競合状態があります。時間の変更(NTPまたはユーザーが変更)がある場合、コードは競合し、クロックは単調ではなくなります。

正しい実装は次のとおりです。

#include <sys/sysctl.h>

static int64_t us_since_boot() {
    struct timeval boottime;
    int mib[2] = {CTL_KERN, KERN_BOOTTIME};
    size_t size = sizeof(boottime);
    int rc = sysctl(mib, 2, &boottime, &size, NULL, 0);
    if (rc != 0) {
      return 0;
    }
    return (int64_t)boottime.tv_sec * 1000000 + (int64_t)boottime.tv_usec;
}

- (int64_t)us_uptime
{
    int64_t before_now;
    int64_t after_now;
    struct timeval now;

    after_now = us_since_boot();
    do {
        before_now = after_now;
        gettimeofday(&now, NULL);
        after_now = us_since_boot();
    } while (after_now != before_now);

    return (int64_t)now.tv_sec * 1000000 + (int64_t)now.tv_usec - before_now;
}
于 2016-11-08T22:54:16.890 に答える
4

より高い精度が必要な場合は、以下は受け入れられた回答の修正版です。

#include <sys/sysctl.h>

- (NSTimeInterval)uptime
{
    struct timeval boottime;
    int mib[2] = {CTL_KERN, KERN_BOOTTIME};
    size_t size = sizeof(boottime);

    struct timeval now;
    struct timezone tz;
    gettimeofday(&now, &tz);

    double uptime = -1;

    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0)
    {
        uptime = now.tv_sec - boottime.tv_sec;
        uptime += (double)(now.tv_usec - boottime.tv_usec) / 1000000.0;
    }
    return uptime;
}
于 2016-03-18T17:50:38.077 に答える
3

Leszekの答えについてコメントしたいのですが、十分な担当者がいません...Leszekのソリューションは数秒を返します。

以下は、ミリ秒の精度が必要な場合のLeszekの回答の修正版です。

#include <sys/sysctl.h>

+ (long long int)uptime 
{
    struct timeval boottime;
    int mib[2] = {CTL_KERN, KERN_BOOTTIME};
    size_t size = sizeof(boottime);

    struct timeval now;
    struct timezone tz;
    gettimeofday(&now, &tz);

    long long int uptime = -1;

    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0)
    {
        uptime = ((long long int)(now.tv_sec - boottime.tv_sec)) * 1000;
        uptime += (now.tv_usec - boottime.tv_usec) / 1000;
    }
    return uptime;
}
于 2017-01-30T15:10:34.873 に答える
-6

systemUptimeを使用しないのはなぜですか?

systemUptimeコンピューターが再起動されてからの経過時間を返します。

  • (NSTimeInterval)systemUptime戻り値コンピューターが再起動されてからの時間を示すNSTimeInterval。

可用性iOS4.0以降で利用できます。NSProcessInfo.hで宣言

私は、少なくともiOS7.1.1を搭載したiPhone5で、電話がロックされてもsystemUptimeが停止しないことをテストして証明しました。したがって、これで自分でテストできるとは誰も信じていません。

于 2014-05-07T04:19:00.603 に答える