उदाहरण के लिए, उद्देश्य-सी में मिलीसेकंड में मुझे एक सटीक समय कैसे मिल सकता है?


99

क्या कोई समय बहुत ही सटीक तरीके से प्राप्त करने का एक आसान तरीका है?

मुझे विधि कॉल के बीच कुछ देरी की गणना करने की आवश्यकता है। विशेष रूप से, मैं एक UIScrollView में स्क्रॉलिंग की गति की गणना करना चाहता हूं।


यहाँ एक बहुत ही संबंधित प्रश्न है जो यहाँ उत्तर को समझने में मदद कर सकता है .. कृपया एक नज़र डालें!
13


जवाबों:


127

NSDateऔर timeIntervalSince*विधियाँ NSTimeIntervalउप-मिलीसेकंड सटीकता के साथ दोहरा है। NSTimeIntervalसेकंड में है, लेकिन यह आपको अधिक सटीकता प्रदान करने के लिए दोहरे का उपयोग करता है।

मिलीसेकंड समय सटीकता की गणना करने के लिए, आप कर सकते हैं:

// Get a current time for where you want to start measuring from
NSDate *date = [NSDate date];

// do work...

// Find elapsed time and convert to milliseconds
// Use (-) modifier to conversion since receiver is earlier than now
double timePassed_ms = [date timeIntervalSinceNow] * -1000.0;

समय पर प्रलेखनInvalvalSinceNow

इस अंतराल का उपयोग करके गणना करने के कई अन्य तरीके हैं NSDate, और मैं कक्षा के दस्तावेज़ीकरण को देखने की सलाह दूंगाNSDate जिसके लिए NSDate क्लास संदर्भ में पाया जाता है ।


3
वास्तव में यह सामान्य उपयोग के मामले के लिए पर्याप्त सटीक है।
लॉगानकोटरेल

4
क्या बीते समय की गणना करने के लिए NSDates का उपयोग करना सुरक्षित है? मुझे लगता है कि बाहरी समय स्रोतों के साथ समन्वय करते समय सिस्टम समय आगे या पीछे जा सकता है, इसलिए आप परिणाम पर भरोसा नहीं कर पाएंगे। आप वास्तव में एक नीरस बढ़ती हुई घड़ी चाहते हैं, क्या नहीं?
क्रिस्टोफर जॉनसन

1
मैंने सिर्फ तुलना की NSDateऔर mach_absolute_time()लगभग 30ms के स्तर पर। २ बनाम २ ९, ३६ बनाम ३ ९, ४३ बनाम ४५। NSDateमेरे लिए इस्तेमाल करना आसान था और नतीजे ध्यान न देने के समान थे।
नेवण राजा

7
NSDate का उपयोग बीते हुए समय की तुलना करने के लिए सुरक्षित नहीं है, क्योंकि सिस्टम घड़ी किसी भी समय बदल सकती है (NTP, DST संक्रमण, लीप सेकंड और कई अन्य कारणों के कारण)। इसके बजाय mach_absolute_time का उपयोग करें।
नेवियान

@nevyn आपने अभी-अभी मेरी इंटरनेट स्पीड टेस्ट, ty बचाई है! धिक्कार है मुझे खुशी है कि मैंने कोड पेस्ट करने से पहले टिप्पणियाँ पढ़ीं हेह
अल्बर्ट रेनशॉ

41

mach_absolute_time() सटीक माप प्राप्त करने के लिए इस्तेमाल किया जा सकता है।

Http://developer.apple.com/qa/qa2004/qa1398.html देखें

यह भी उपलब्ध है CACurrentMediaTime(), जो अनिवार्य रूप से एक ही चीज़ है, लेकिन एक आसान-से-उपयोग इंटरफ़ेस के साथ।

(नोट: यह उत्तर 2009 में लिखा गया था। clock_gettime()मैकले और आईओएस के नए संस्करणों में उपलब्ध सरल पॉसिक्स इंटरफेस के लिए पावेल अलेक्सीव का उत्तर देखें ।)


1
उस कोड में एक अजीब रूपांतरण है - पहले उदाहरण की अंतिम पंक्ति "वापसी * ​​(uint64_t *) & elapsedNano;" क्यों नहीं "वापसी (uint64_t) बीता हुआ" नैनो?
टायलर

8
कोर एनिमेशन (QuartzCore.framework) एक सुविधा पद्धति भी प्रदान करता है CACurrentMediaTime(), जो mach_absolute_time()सीधे एक में परिवर्तित होता है double
ओटो

1
@ टायलर, elapsedNanoप्रकार का होता है Nanoseconds, जो एक सादे पूर्णांक प्रकार नहीं है। यह एक उपनाम है UnsignedWide, जो दो 32-बिट पूर्णांक फ़ील्ड के साथ एक संरचना है। आप UnsignedWideToUInt64()चाहें तो कलाकारों के बजाय उपयोग कर सकते हैं।
केन थॉमासेस

CoreServices केवल एक मैक लाइब्रेरी है। क्या आईओएस में एक बराबर है?
मिमी 24

1
@ mm24 iOS पर, CACurrentMediaTime () का उपयोग करें, जो कि कोर एनिमेशन में है।
क्रिस्टोफर जॉनसन

28

कृपया उपयोग न करें NSDate, CFAbsoluteTimeGetCurrentया gettimeofdayबीत चुके समय को मापने के लिए। ये सभी सिस्टम घड़ी पर निर्भर करते हैं, जो किसी भी समय कई अलग-अलग कारणों से बदल सकते हैं , जैसे कि नेटवर्क टाइम सिंक (NTP) घड़ी को अपडेट करना (अक्सर बहाव के लिए समायोजित करने के लिए होता है), डीएसटी समायोजन, लीप सेकंड, और इसी तरह।

इसका मतलब है कि यदि आप अपनी डाउनलोड या अपलोड गति को माप रहे हैं, तो आपको अपने नंबरों में अचानक स्पाइक्स या बूंदें मिलेंगी जो वास्तव में जो कुछ भी नहीं हुआ था, उससे संबंधित नहीं हैं; आपके प्रदर्शन परीक्षणों में अजीब गलत परिणाम होंगे; और आपकी मैनुअल टाइमर गलत अवधि के बाद ट्रिगर हो जाएगी। समय भी पीछे की ओर जा सकता है, और आप नकारात्मक डेल्टा के साथ समाप्त होते हैं, और आप अनंत पुनरावृत्ति या मृत कोड (हाँ, मैंने इन दोनों को किया है) के साथ समाप्त हो सकता है।

का उपयोग करें mach_absolute_time। कर्नेल बूट होने के बाद से यह वास्तविक सेकंड मापता है। यह नीरस रूप से बढ़ रहा है (कभी भी पीछे नहीं हटेगा), और तारीख और समय सेटिंग से अप्रभावित है। चूंकि यह काम करने के लिए एक दर्द है, यहाँ एक सरल आवरण है जो आपको देता है NSTimeInterval:

// LBClock.h
@interface LBClock : NSObject
+ (instancetype)sharedClock;
// since device boot or something. Monotonically increasing, unaffected by date and time settings
- (NSTimeInterval)absoluteTime;

- (NSTimeInterval)machAbsoluteToTimeInterval:(uint64_t)machAbsolute;
@end

// LBClock.m
#include <mach/mach.h>
#include <mach/mach_time.h>

@implementation LBClock
{
    mach_timebase_info_data_t _clock_timebase;
}

+ (instancetype)sharedClock
{
    static LBClock *g;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        g = [LBClock new];
    });
    return g;
}

- (id)init
{
    if(!(self = [super init]))
        return nil;
    mach_timebase_info(&_clock_timebase);
    return self;
}

- (NSTimeInterval)machAbsoluteToTimeInterval:(uint64_t)machAbsolute
{
    uint64_t nanos = (machAbsolute * _clock_timebase.numer) / _clock_timebase.denom;

    return nanos/1.0e9;
}

- (NSTimeInterval)absoluteTime
{
    uint64_t machtime = mach_absolute_time();
    return [self machAbsoluteToTimeInterval:machtime];
}
@end

2
धन्यवाद। CACurrentMediaTime()क्वार्ट्जकोर से क्या ?
कूर

1
नोट: कोई भी @import Darwin;इसके बजाय का उपयोग कर सकता है#include <mach/mach_time.h>
Cœur

@ C @ur CACurrentMediaTime को वास्तव में मेरे कोड के बराबर होना चाहिए। अच्छा खोजो! (हैदर का कहना है "यह mach_absolute_time को कॉल करने का परिणाम है () और इकाइयों को सेकंड में परिवर्तित करना")
nevyn

"कई अलग-अलग कारणों से किसी भी समय बदल सकता है, जैसे कि नेटवर्क टाइम सिंक (NTP) घड़ी को अपडेट करना (अक्सर बहाव के लिए समायोजित करने के लिए होता है), DST समायोजन, लीप सेकंड, और इसी तरह।" - और क्या कारण हो सकते हैं? मैं इंटरनेट कनेक्शन नहीं होने के दौरान लगभग 50 एमएस के पिछड़े कूदता देख रहा हूं। तो, जाहिर है, इनमें से कोई भी कारण लागू नहीं होना चाहिए ...
फाल्को

@ फालो को यकीन नहीं है, लेकिन अगर मुझे अनुमान लगाना है, तो मैं दांव लगाऊंगा कि अगर यह अलग हार्डवेयर घड़ियों को सिंक से बाहर कर रहा है, तो ओएस अपने दम पर मुआवजे का बहाव करेगा?
नेविन

14

CFAbsoluteTimeGetCurrent()एक के रूप में पूर्ण समय रिटर्न doubleमूल्य है, लेकिन मैं नहीं पता है क्या अपने सटीक है - यह हो सकता है केवल हर दर्जन मिलीसेकेंड अद्यतन, या यह, मैं नहीं जानता कि हर माइक्रोसेकंड अपडेट कर सकते हैं।


2
यह एक डबल-सटीक फ़्लोटिंग-पॉइंट मान है, और उप-मिलीसेकंड सटीकता प्रदान करता है। 72.89674947369 सेकंड का मान असामान्य नहीं है ...
जिम डोवी

25
@JimDovey: मुझे कहना होगा कि 72.89674947369सेकंड का एक मूल्य बहुत ही असामान्य होगा, अन्य सभी मूल्यों को देखते हुए यह हो सकता है। ;)
FreeAsInBeer

3
@ जिम: क्या आपके पास एक उद्धरण है कि यह उप-मिलीसेकंड सटीकता प्रदान करता है (यह एक ईमानदार सवाल है)? मुझे उम्मीद है कि यहां हर कोई सटीकता और सटीकता के बीच के अंतर को समझता है ।
एडम रोसेनफील्ड

5
CFAbsoluteTimeGetCurrent () OS X पर Gettimeofday () और GetSystemTimeAsFileTime () विंडोज पर कॉल करता है। यहाँ स्रोत कोड है
जिम डोवे

3
ओह, और gettimeofday () mach_absolute_time () के माध्यम से मच नैनोसेकंड टाइमर का उपयोग करके कार्यान्वित किया जाता है ; डार्विन / एआरएम पर gettimeofday () के सामान्य-पृष्ठ कार्यान्वयन के लिए यहां एक स्रोत है: filesource.apple.com/source/Libc/Libc-763.12/arm/sys/…
जिम डोवी

10

मैं mach_absolute_time()इसका उपयोग नहीं करूंगा क्योंकि यह टिक्स (शायद एक अपटाइम) का उपयोग करके पूर्ण समय के लिए कर्नेल और प्रोसेसर के संयोजन पर सवाल उठाता है।

मैं क्या उपयोग करेगा:

CFAbsoluteTimeGetCurrent();

यह फ़ंक्शन iOS और OSX सॉफ़्टवेयर और हार्डवेयर में अंतर को ठीक करने के लिए अनुकूलित है।

कुछ गीकियर

में एक फर्क का भागफल mach_absolute_time()और AFAbsoluteTimeGetCurrent()हमेशा के आसपास 24000011.154871 है

यहाँ मेरे ऐप का एक लॉग है:

कृपया ध्यान दें कि अंतिम परिणाम समय में एक फर्क है CFAbsoluteTimeGetCurrent()की

 2012-03-19 21:46:35.609 Rest Counter[3776:707] First Time: 353900795.609040
 2012-03-19 21:46:36.360 Rest Counter[3776:707] Second Time: 353900796.360177
 2012-03-19 21:46:36.361 Rest Counter[3776:707] Final Result Time (difference): 0.751137
 2012-03-19 21:46:36.363 Rest Counter[3776:707] Mach absolute time: 18027372
 2012-03-19 21:46:36.365 Rest Counter[3776:707] Mach absolute time/final time: 24000113.153295
 2012-03-19 21:46:36.367 Rest Counter[3776:707] -----------------------------------------------------
 2012-03-19 21:46:43.074 Rest Counter[3776:707] First Time: 353900803.074637
 2012-03-19 21:46:43.170 Rest Counter[3776:707] Second Time: 353900803.170256
 2012-03-19 21:46:43.172 Rest Counter[3776:707] Final Result Time (difference): 0.095619
 2012-03-19 21:46:43.173 Rest Counter[3776:707] Mach absolute time: 2294833
 2012-03-19 21:46:43.175 Rest Counter[3776:707] Mach absolute time/final time: 23999753.727777
 2012-03-19 21:46:43.177 Rest Counter[3776:707] -----------------------------------------------------
 2012-03-19 21:46:46.499 Rest Counter[3776:707] First Time: 353900806.499199
 2012-03-19 21:46:55.017 Rest Counter[3776:707] Second Time: 353900815.016985
 2012-03-19 21:46:55.018 Rest Counter[3776:707] Final Result Time (difference): 8.517786
 2012-03-19 21:46:55.020 Rest Counter[3776:707] Mach absolute time: 204426836
 2012-03-19 21:46:55.022 Rest Counter[3776:707] Mach absolute time/final time: 23999996.639500
 2012-03-19 21:46:55.024 Rest Counter[3776:707] -----------------------------------------------------

मैं mach_absolute_time()एक का उपयोग कर समाप्त हो गया mach_timebase_info_dataऔर फिर किया (long double)((mach_absolute_time()*time_base.numer)/((1000*1000)*time_base.denom));। मच (void)mach_timebase_info(&your_timebase);
टाइमबेस

12
CFAbsoluteTimeGetCurrent () के लिए डॉक्स के अनुसार, "सिस्टम समय बाहरी समय संदर्भों के साथ सिंक्रनाइज़ेशन के कारण या घड़ी के स्पष्ट उपयोगकर्ता परिवर्तन के कारण घट सकता है।" मुझे समझ में नहीं आता है कि क्यों किसी को बीते हुए समय को मापने के लिए इस तरह का उपयोग करना होगा, अगर यह पीछे की तरफ जा सकता है।
क्रिस्टोफर जॉनसन

6
#define CTTimeStart() NSDate * __date = [NSDate date]
#define CTTimeEnd(MSG) NSLog(MSG " %g",[__date timeIntervalSinceNow]*-1)

उपयोग:

CTTimeStart();
...
CTTimeEnd(@"that was a long time:");

आउटपुट:

2013-08-23 15:34:39.558 App-Dev[21229:907] that was a long time: .0023

NSDateसिस्टम घड़ी पर निर्भर करता है जिसे किसी भी समय बदला जा सकता है, जिसके परिणामस्वरूप गलत या नकारात्मक समय अंतराल हो सकता है। mach_absolute_timeसही समय बीतने के बजाय उपयोग करें ।
कूर

mach_absolute_timeडिवाइस रिबूट से प्रभावित हो सकता है। इसके बजाय सर्वर-टाइम का उपयोग करें।
केलिन

5

इसके अलावा, यहां बताया गया है कि NSNumberमिलीसेकंड में यूनिक्स युग के साथ 64-बिट की गणना कैसे की जाती है , इस मामले में कि आप इसे कोरडाटा में कैसे स्टोर करना चाहते हैं। मुझे अपने ऐप के लिए इसकी आवश्यकता थी जो एक सिस्टम के साथ इंटरैक्ट करता है जो इस तरह से स्टोर करता है।

  + (NSNumber*) longUnixEpoch {
      return [NSNumber numberWithLongLong:[[NSDate date] timeIntervalSince1970] * 1000];
  }

3

mach_absolute_timeलघु माप के आधार पर कार्य अच्छे हैं।
लेकिन लंबे माप के लिए महत्वपूर्ण कैवेट यह है कि वे उपकरण के सोते समय टिक करना बंद कर देते हैं।

बूट के बाद से समय प्राप्त करने के लिए एक फ़ंक्शन है। यह सोते समय नहीं रुकता। इसके अलावा, gettimeofdayमोनोटोनिक नहीं है, लेकिन मेरे प्रयोगों में मैंने हमेशा देखा है कि जब सिस्टम समय बदलता है तो बूट समय बदलता है, इसलिए मुझे लगता है कि इसे ठीक काम करना चाहिए।

func timeSinceBoot() -> TimeInterval
{
    var bootTime = timeval()
    var currentTime = timeval()
    var timeZone = timezone()

    let mib = UnsafeMutablePointer<Int32>.allocate(capacity: 2)
    mib[0] = CTL_KERN
    mib[1] = KERN_BOOTTIME
    var size = MemoryLayout.size(ofValue: bootTime)

    var timeSinceBoot = 0.0

    gettimeofday(&currentTime, &timeZone)

    if sysctl(mib, 2, &bootTime, &size, nil, 0) != -1 && bootTime.tv_sec != 0 {
        timeSinceBoot = Double(currentTime.tv_sec - bootTime.tv_sec)
        timeSinceBoot += Double(currentTime.tv_usec - bootTime.tv_usec) / 1000000.0
    }
    return timeSinceBoot
}

और iOS 10 और macOS 10.12 के बाद से हम CLOCK_MONOTONIC का उपयोग कर सकते हैं:

if #available(OSX 10.12, *) {
    var uptime = timespec()
    if clock_gettime(CLOCK_MONOTONIC_RAW, &uptime) == 0 {
        return Double(uptime.tv_sec) + Double(uptime.tv_nsec) / 1000000000.0
    }
}

इसका सारांश प्रस्तुत करना:

  • Date.timeIntervalSinceReferenceDate - जब सिस्टम समय बदलता है, तो मोनोटोनिक नहीं
  • CFAbsoluteTimeGetCurrent() - मोनोटोनिक नहीं, पीछे जा सकता है
  • CACurrentMediaTime() - जब डिवाइस सो रहा हो तब टिक करना बंद कर देता है
  • timeSinceBoot() - नींद नहीं आती है, लेकिन मोनोटोनिक नहीं हो सकता है
  • CLOCK_MONOTONIC IOS 10 के बाद से समर्थित, नींद, नीरस नहीं है

1

मुझे पता है कि यह एक पुराना है, लेकिन यहां तक ​​कि मैंने खुद को फिर से अतीत में भटकते पाया, इसलिए मैंने सोचा कि मैं यहां अपना विकल्प प्रस्तुत करूंगा।

इस पर मेरे ब्लॉग पोस्ट को देखने के लिए सबसे अच्छी शर्त है: ऑब्जेक्टिव-सी में टाइमिंग चीजें: एक स्टॉपवॉच

मूल रूप से, मैंने एक वर्ग लिखा है जो बहुत ही बुनियादी तरीके से देखना बंद कर देता है, लेकिन इसे संक्षिप्त किया जाता है ताकि आपको केवल निम्नलिखित कार्य करने की आवश्यकता हो:

[MMStopwatchARC start:@"My Timer"];
// your work here ...
[MMStopwatchARC stop:@"My Timer"];

और आप के साथ अंत:

MyApp[4090:15203]  -> Stopwatch: [My Timer] runtime: [0.029]

लॉग में ...

दोबारा, मेरी पोस्ट को थोड़ा और देखें या इसे यहाँ डाउनलोड करें: MMStopwatch.zip


आपके कार्यान्वयन की अनुशंसा नहीं की जाती है। NSDateसिस्टम घड़ी पर निर्भर करता है जिसे किसी भी समय बदला जा सकता है, जिसके परिणामस्वरूप गलत या नकारात्मक समय अंतराल हो सकता है। mach_absolute_timeसही समय बीतने के बजाय उपयोग करें ।
कूर

1

NSDate का उपयोग करके आप पहली जनवरी, 1970 से मिलीसेकंड में वर्तमान समय प्राप्त कर सकते हैं:

- (double)currentTimeInMilliseconds {
    NSDate *date = [NSDate date];
    return [date timeIntervalSince1970]*1000;
}

यह आपको मिलीसेकंड में समय देता है, लेकिन यह अभी भी सटीक है
dev

-1

उन लोगों के लिए हमें @ जेफ थॉम्पसन के उत्तर के स्विफ्ट संस्करण की आवश्यकता है:

// Get a current time for where you want to start measuring from
var date = NSDate()

// do work...

// Find elapsed time and convert to milliseconds
// Use (-) modifier to conversion since receiver is earlier than now
var timePassed_ms: Double = date.timeIntervalSinceNow * -1000.0

उम्मीद है इससे आपको मदद होगी।


2
NSDateसिस्टम घड़ी पर निर्भर करता है जिसे किसी भी समय बदला जा सकता है, जिसके परिणामस्वरूप गलत या नकारात्मक समय अंतराल हो सकता है। उपयोगmach_absolute_timeसही समय बीतने के बजाय ।
कूर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.