2012-07-01 38 views
8

Có API nào để có được NSDate hoặc NSTimeInterval đại diện cho thời gian hệ thống khởi động không? Một số API chẳng hạn như [NSProcessInfo systemUptime] và thời gian trả về Core Motion kể từ khi khởi động. Tôi cần phải tương quan chính xác các giá trị thời gian hoạt động này với NSDate s, khoảng một phần nghìn giây.Lấy thời gian khởi động hệ thống chính xác trên iOS/OS X

Thời gian từ khi khởi động cung cấp độ chính xác cao hơn, nhưng dễ dàng thấy rằng NSDate đã cung cấp độ chính xác theo thứ tự 100 nano giây và bất kỳ thứ gì dưới một micro giây chỉ đo độ trễ ngắt và jitter đồng hồ PCB.

Điều hiển nhiên là trừ thời gian hoạt động từ thời điểm hiện tại [NSDate date]. Nhưng giả định rằng thời gian không thay đổi giữa hai cuộc gọi hệ thống, đó là, tốt, khó thực hiện. Hơn nữa nếu thread được preempted giữa các cuộc gọi, tất cả mọi thứ được ném ra. Cách giải quyết là lặp lại quá trình nhiều lần và sử dụng kết quả nhỏ nhất, nhưng yuck.

NSDate phải có bộ đệm chính để sử dụng để tạo đối tượng với thời gian hiện tại từ thời gian hoạt động của hệ thống, có thực sự không có cách nào để lấy nó?

+0

Bạn đã chấp nhận câu trả lời, nhưng như @ hotpaw2 đã lưu ý, 'NSDate' là dấu thời gian trên tường và các thay đổi như tiết kiệm ánh sáng ban ngày và cập nhật NTP có thể gây ra hai khoảnh khắc liên tiếp theo thời gian thực 'NSDate' s (hoặc 'time_t's hoặc bất kỳ dấu thời gian nào khác của đồng hồ treo tường.) –

+0

@JonathanGrynspan Thực ra vấn đề không được giải quyết cho sự hài lòng của tôi. Có vẻ như Apple không hề tạo ra các dấu thời gian mạnh mẽ, mặc dù đã thay đổi định dạng giữa CoreLocation và CoreMotion trong một nỗ lực cải tiến rõ ràng. Tiết kiệm ánh sáng ban ngày ít nhất không nên tạo sự khác biệt khi NSDate đo lường GMT. Đối với những gì nó có giá trị ứng dụng của tôi sẽ yêu cầu chế độ máy bay "cho hiệu suất tối ưu" như nhận cuộc gọi là xấu cho hoạt động thời gian thực. Điều này cũng sẽ ngăn chặn NTP. – Potatoswatter

+0

Bạn đang cố gắng đạt được điều gì? Bạn cần có những dấu hiệu cụ thể nào cho dấu thời gian chính xác? Apple thực hiện các dấu thời gian khá giống với cách mà mọi hệ thống khác thực hiện, chỉ với các tên kiểu khác nhau. –

Trả lời

6

Trong OSX, bạn có thể sử dụng sysctl(). Đây là cách tiện ích OSX Unix uptime thực hiện điều đó. Source code khả dụng - tìm kiếm boottime.

Mặc dù vậy, trong iOS, tôi không biết liệu điều này có hiệu quả hay không.

UPDATE: tìm thấy một số mã :)

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

xem nếu làm việc này ...

+0

Ooh, nó thậm chí còn trả về định dạng điểm cố định. Đó là giá trị một thử ... – Potatoswatter

+0

tôi thậm chí còn nhớ nhìn thấy một số mã ở đâu đó để có được boottime, hãy để tôi tìm thấy nó cho bạn. –

+0

không phải lo lắng: v) ... – Potatoswatter

0

Các thói quen bên mach/mach_time.h được đảm bảo để được tăng đơn điệu, không giống như NSDate.

+0

NSDate tăng theo tốc độ không đổi theo thời gian, tất nhiên, nhưng tần suất thay đổi thay đổi. Hiện tại nó ~ 100 ns, trong khoảng 5 năm nó sẽ chuyển sang ~ 200 ns, 20 năm sau đó ~ 400 ns. Điều đó sẽ không phá vỡ nhiều ứng dụng… mặc dù tôi không nói rằng dấu phẩy động là một cách tốt để đại diện cho thời gian. – Potatoswatter

+2

@Potatoeswatter: Không đúng sự thật.Hai cuộc gọi NSDate liên tiếp có thể quay ngược thời gian (nếu chỉnh sửa NTP rơi theo hướng đó ở giữa). Xem diễn đàn của Apple Developer để xác minh điều này. – hotpaw2

+0

OK, thú vị. Nhưng điều này vẫn không phải là câu trả lời cho câu hỏi. Tôi được cung cấp một NSDate bởi CoreLocation và một NSTimeInterval bởi CoreMotion; Tôi không thể chọn đại diện. Có cách nào để tạm thời vô hiệu hóa NTP trong khi ứng dụng của tôi thực thi trên iOS không? – Potatoswatter

2

Câu trả lời được chấp nhận, sử dụng systcl, hoạt động, nhưng các giá trị được trả về bởi sysctl cho KERN_BOOTTIME, ít nhất là trong thử nghiệm của tôi (Darwin Kernel Version 11.4.2), luôn toàn bộ giây (lĩnh vực micro, tv_usec, là 0). Điều này có nghĩa là thời gian kết quả có thể lên tới 1 giây, điều này không chính xác lắm. Ngoài ra, khi so sánh giá trị đó, với giá trị được lấy từ thực nghiệm từ sự khác biệt giữa REALTIME_CLOCKCALENDAR_CLOCK, đôi khi chúng khác nhau trong vài giây, vì vậy không rõ ràng giá trị KERN_BOOTTIME có tương ứng chính xác với thời gian hoạt động hay không đồng hồ.

1

Có một cách khác. Nó có thể cho kết quả hơi khác (ít hoặc nhiều hơn) so với accepted answer

Tôi đã so sánh chúng. Tôi nhận được sự khác biệt -7 giây cho OSX 10.9.3 và +2 giây cho iOS 7.1.1

Khi tôi hiểu cách này cho kết quả tương tự nếu đồng hồ treo tường thay đổi, nhưng câu trả lời được chấp nhận cho kết quả khác nhau nếu đồng hồ treo tường thay đổi ...

Đây mã:

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

macro COUNT_ARRAY_ELEMS được xác định ở đâu? –

+1

tôi giả sử #define COUNT_ARRAY_ELEMS (arr) sizeof (arr)/sizeof (arr [0]) –

+0

Trước hết, tôi không thực sự hiểu mã bạn đã viết. Sau đó, tôi quyết định thử nghiệm nó, kết quả vẫn như cũ nhưng có vẻ vô nghĩa nếu tôi in kết quả dưới dạng thời gian có thể đọc được: "Thứ Tư, ngày 31 tháng 12 năm 1969 lúc 4:00:00 giờ chuẩn Thái Bình Dương." (Lưu ý năm: 1969) Tôi có bị mất gì không? –

0

Reffer để thể loại này

.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 
Các vấn đề liên quan