获取iOS / OS X系统启动的准确时间
是否有一个API来获得代表系统启动时间的NSDate
或NSTimeInterval
? 一些API,例如[NSProcessInfo systemUptime]
和Core Motion自引导以来的返回时间。 我需要精确地将这些正常运行时间值与NSDate
相关联,大约一毫秒。
自启动以来的时间表面上提供了更高的精度,但很容易看出NSDate
已经提供了大约100纳秒的精度,而微秒级以下的任何事情都只是测量中断延迟和PCB时钟抖动。
显而易见的是从当前时间[NSDate date]
减去正常运行时间。 但是,假定两个系统调用之间的时间不会改变,这很难完成。 而且,如果线程在调用之间被抢占,所有东西都被抛弃了。 解决方法是多次重复该过程,并使用最小的结果,但是y。。
NSDate
必须有一个主偏移量,它用来从系统正常运行时间生成当前时间的对象,是否真的没有办法获得它?
在OSX中,你可以使用sysctl() 。 这就是OSX Unix实用程序uptime
方式。 源代码可用 – search启动时间。
公平的警告,但在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]; }
看看这是否工作…
使用systcl
的接受的答案是有效的,但至less在我的testing(Darwin Kernel Version 11.4.2)中, sysctl
为KERN_BOOTTIME
返回的值始终是整秒(微秒字段tv_usec
为0)。 这意味着结果时间可能会达到1秒,这不是很准确。
此外,将这个值与实验得出的REALTIME_CLOCK
和CALENDAR_CLOCK
之间的差异进行比较,它们有时相差几秒钟,所以不清楚KERN_BOOTTIME
值是否与正常运行时间的时间基本一致。
还有另一种方法。 它可能给出的结果与接受的答案略有不同(更less或更多)
我比较了他们。 OSX 10.9.3的差异是-7秒,iOS 7.1.1的是+2秒
据我所知,这种方式给出了相同的结果,如果墙上时钟改变,但接受的答案给出不同的结果,如果墙上的时钟改变…
这里代码:
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; }
mach / mach_time.h中的例程保证单调递增,与NSDate不同。
反对这个类别
。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