9

是否有 API 来获取NSDateNSTimeInterval表示系统启动的时间?某些 API,例如[NSProcessInfo systemUptime]Core Motion 和自启动后的返回时间。我需要将这些正常运行时间值与NSDates 精确关联到大约一毫秒。

自启动以来的时间表面上提供了更高的精度,但很容易看出它NSDate已经提供了大约 100 纳秒的精度,而任何低于微秒的时间都只是测量中断延迟和 PCB 时钟抖动。

显而易见的是从当前时间中减去正常运行时间[NSDate date]。但这假设两个系统调用之间的时间没有变化,这很难实现。此外,如果线程在调用之间被抢占,一切都会被抛弃。解决方法是多次重复该过程并使用最小的结果,但是很糟糕。

NSDate必须有一个主偏移量,用于从系统正常运行时间生成具有当前时间的对象,真的没有办法获得吗?

4

5 回答 5

8

在 OSX 中,您可以使用sysctl()。这就是 OSX Unix 实用程序的uptime工作方式。 源代码可用 - 搜索boottime.

不过,公平的警告,在 iOS 中,我不知道这是否可行。

更新:找到一些代码:)

#include <sys/types.h>
#include <sys/sysctl.h>  

#define MIB_SIZE 2  

int mib[MIB_SIZE];
size_t size;
struct timeval  boottime;

mib[0] = CTL_KERN;
mib[1] = KERN_BOOTTIME;
size = sizeof(boottime);
if (sysctl(mib, MIB_SIZE, &boottime, &size, NULL, 0) != -1)
{
    // successful call
    NSDate* bootDate = [NSDate dateWithTimeIntervalSince1970:
                               boottime.tv_sec + boottime.tv_usec / 1.e6];
}

看看这是否有效...

于 2012-07-01T14:56:23.183 回答
2

接受的答案 usingsystcl有效,但 for 返回的值sysctlKERN_BOOTTIME至少在我的测试(达尔文内核版本 11.4.2)中,总是以整秒为单位(微秒字段tv_usec, 为 0)。这意味着生成的时间可能最多 1 秒,这不是很准确。

此外,将该值与从 和 之间的差异通过实验得出的值进行比较后REALTIME_CLOCKCALENDAR_CLOCK它们有时会相差几秒钟,因此尚不清楚该KERN_BOOTTIME值是否与正常运行时间时钟的时基完全对应。

于 2012-11-29T19:58:39.867 回答
1

There is another way. It could give result slightly different (less or more) than accepted answer

I have compared them. I get difference -7 second for OSX 10.9.3 and +2 second for iOS 7.1.1

As i understand this way gives same result if wall clock changed, but accepted answer gives different results if wall clock changed...

Here code:

static CFAbsoluteTime getKernelTaskStartTime(void) {
    enum { MICROSECONDS_IN_SEC = 1000 * 1000 };
    struct kinfo_proc   info;
    bzero(&info, sizeof(info));

    // Initialize mib, which tells sysctl the info we want, in this case
    // we're looking for information about a specific process ID = 0.
    int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, 0};

    // Call sysctl.
    size_t size = sizeof(info);
    const int sysctlResult = sysctl(mib, COUNT_ARRAY_ELEMS(mib), &info, &size, NULL, 0);
    assert(0 != sysctlResult);

    const struct timeval * timeVal = &(info.kp_proc.p_starttime);
    NSTimeInterval result = -kCFAbsoluteTimeIntervalSince1970;
    result += timeVal->tv_sec;
    result += timeVal->tv_usec / (double)MICROSECONDS_IN_SEC;
    return result;
}
于 2014-06-27T12:49:37.703 回答
1

参考这个类别

NSDate+BootTime.h

#import <Foundation/Foundation.h>

@interface NSDate (BootTime)

+ (NSDate *)bootTime;

+ (NSTimeInterval)bootTimeTimeIntervalSinceReferenceDate;

@end

NSDate+BootTime.m

#import "NSDate+BootTime.h"

#include <sys/types.h>
#include <sys/sysctl.h>

@implementation NSDate (BootTime)

+ (NSDate *)bootTime {
    return [NSDate dateWithTimeIntervalSinceReferenceDate:[NSDate bootTimeTimeIntervalSinceReferenceDate]];
}

+ (NSTimeInterval)bootTimeTimeIntervalSinceReferenceDate {
    return getKernelTaskStartTime();
}

////////////////////////////////////////////////////////////////////////
#pragma mark - Private
////////////////////////////////////////////////////////////////////////

#define COUNT_ARRAY_ELEMS(arr) sizeof(arr)/sizeof(arr[0])

static CFAbsoluteTime getKernelTaskStartTime(void) {
    enum { MICROSECONDS_IN_SEC = 1000 * 1000 };
    struct kinfo_proc   info;
    bzero(&info, sizeof(info));

    // Initialize mib, which tells sysctl the info we want, in this case
    // we're looking for information about a specific process ID = 0.
    int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, 0};

    // Call sysctl.
    size_t size = sizeof(info);
    const int sysctlResult = sysctl(mib, COUNT_ARRAY_ELEMS(mib), &info, &size, NULL, 0);
    if (sysctlResult != -1) {

        const struct timeval * timeVal = &(info.kp_proc.p_starttime);
        NSTimeInterval result = -kCFAbsoluteTimeIntervalSince1970;
        result += timeVal->tv_sec;
        result += timeVal->tv_usec / (double)MICROSECONDS_IN_SEC;
        return result;

    }

    return 0;
}

@end
于 2015-08-03T13:51:32.803 回答
0

与 NSDate 不同,mach/mach_time.h 中的例程保证单调递增。

于 2012-07-01T15:15:20.767 回答