2012-07-01 84 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