2012-07-01 37 views
8

是否有获取代表系统启动时间的NSDateNSTimeInterval的API?一些API,例如[NSProcessInfo systemUptime]和Core Motion自启动以来的返回时间。我需要将这些正常运行时间值与NSDate s精确关联,大约一毫秒。获取iOS/OS X系统启动的准确时间X

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

显而易见的是减去当前时间[NSDate date]的正常运行时间。但是,这假定两次系统调用之间的时间不会改变,这很难完成。而且,如果线程在调用之间被抢占,所有内容都将被抛出。解决方法是多次重复该过程并使用最小的结果,但是糟糕。

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

+0

你已经接受了一个答案,但正如@ hotpaw2指出的那样,'NSDate'是一个挂钟时间戳,而诸如夏时制和NTP更新之类的更改可能导致两个连续时刻实时显示错误顺序, 'NSDate's(或'time_t's或任何其他挂钟时间戳。) –

+0

@JonathanGrynspan确实问题没有得到解决,我的满意。看起来Apple虽然已经改变了CoreLocation和CoreMotion之间的格式,但显然还未尝试改进,但它完全没有生成稳健的时间戳。由于NSDate测量GMT,夏时制至少不应有所作为。因为接收电话对于实时操作而言不好,所以我的应用程序会要求飞行模式“最佳性能”。这也会阻止NTP。 – Potatoswatter

+0

你想达到什么目的?您对精确时间戳有什么具体需求?苹果公司的时间戳几乎与其他系统一样,只是使用不同的类型名称。 –

回答

6

在OSX中,您可以使用sysctl()。这是OSX Unix实用程序uptime如何执行的。 Source code可用 - 搜索boottime

公平的警告,但在iOS我不知道这是否会工作。

UPDATE:发现了一些代码:)

#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]; 
} 

看看,如果这个工程...

+0

哦,它甚至可以返回更为稳定的定点格式。这是值得一试... – Potatoswatter

+0

我甚至记得看到一些代码来获取启动时间,让我为你找到它。 –

+0

不用担心:v)... – Potatoswatter

0

马赫/ mach_time.h内的程序保证是单调递增的,不像NSDate的。

+0

当然,随着时间的推移,NSDate以恒定的速率增加,但变化的频率不同。目前它约为100ns,在大约5年内它将转换到约200ns,在约400ns之后20年。这不会破坏很多应用程序......尽管我并不是说浮点代表时间的好方法。 – Potatoswatter

+2

@Potatoeswatter:不正确。两个连续的NSDate调用可以及时倒退(如果NTP纠正在这个方向之间)。请参阅Apple开发人员论坛来验证这一点。 – hotpaw2

+0

好的,有趣。但这仍然不是问题的答案。 CoreLocation给出了一个NSDate,CoreMotion给出了一个NSTimeInterval;我不能选择表示。我的应用在iOS上执行时是否有办法暂时禁用NTP? – Potatoswatter

2

接受的答案,使用systcl,工作,但通过sysctlKERN_BOOTTIME返回的值,至少在我的测试(Darwin内核版本11.4.2),总是在整个秒(微秒场,tv_usec,为0 )。这意味着结果时间可能会长达1秒,这不是很准确。

而且,具有比较该值,对一个从REALTIME_CLOCKCALENDAR_CLOCK之间的差试验得到的,他们有时由几秒钟不同,所以它不是明确有无KERN_BOOTTIME值精确地相应于时间基础的正常运行时间时钟。

1

还有另一种方法。它可以给结果比accepted answer

我比较他们略有不同(更多或更少)。我得到的区别-7秒OSX 10.9.3和+2秒的iOS 7.1.1

据我了解这种方式给出相同的结果,如果挂钟改变,但接受的答案给出,如果挂钟改变不同的结果?

下面的代码:

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; 
} 
+0

其中是定义了COUNT_ARRAY_ELEMS宏吗? –

+1

我想#define COUNT_ARRAY_ELEMS(arr)sizeof(arr)/ sizeof(arr [0]) –

+0

首先,我不太了解你写的代码。然后我决定对它进行测试,结果保持不变,但如果我将结果打印为可读时间,则结果保持不变:“1969年12月31日星期三太平洋标准时间下午4:00:00。” (注意:1969年)我有没有失去什么? –

0

Reffer到这一类

.H

#import <Foundation/Foundation.h> 

@interface NSDate (BootTime) 

+ (NSDate *)bootTime; 

+ (NSTimeInterval)bootTimeTimeIntervalSinceReferenceDate; 

@end 

.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