Objective-C에서 예를 들어 밀리 초 단위로 정확한 시간을 어떻게 얻을 수 있습니까?


99

매우 정확하게 시간을 얻는 쉬운 방법이 있습니까?

메서드 호출 간의 지연을 계산해야합니다. 보다 구체적으로 UIScrollView에서 스크롤 속도를 계산하고 싶습니다.


여기 에 답변을 이해하는 데 도움이 될 수있는 매우 많은 관련 질문이 있습니다.
abbood


답변:


127

NSDate그리고 timeIntervalSince*메소드는 반환 NSTimeInterval밀리 초 이하의 정확도로 이중 인을. NSTimeInterval초 단위이지만 더 큰 정밀도를 제공하기 위해 double을 사용합니다.

밀리 초 시간 정확도를 계산하기 위해 다음을 수행 할 수 있습니다.

// 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;

timeIntervalSinceNow에 대한 문서 .

을 사용하여이 간격을 계산하는 다른 많은 방법이 있으며 NSDate Class ReferenceNSDate 에있는 클래스 문서를 참조 NSDate하는 것이 좋습니다 .


3
실제로 이것은 일반적인 사용 사례에 대해 충분히 정확합니다.
logancautrell

4
NSDates를 사용하여 경과 시간을 계산하는 것이 안전합니까? 외부 시간 소스와 동기화 할 때 시스템 시간이 앞뒤로 이동할 수 있으므로 결과를 신뢰할 수없는 것 같습니다. 당신은 정말로 단조롭게 증가하는 시계를 원하지 않습니까?
Kristopher Johnson

1
나는 방금 비교 NSDate했고 mach_absolute_time()약 30ms 수준에서. 27 vs. 29, 36 vs. 39, 43 vs. 45. NSDate는 사용하기 쉬웠고 결과는 신경 쓰지 않을 정도로 비슷했습니다.
nevan king

7
NSDate를 사용하여 경과 시간을 비교하는 것은 안전하지 않습니다. 시스템 시계는 언제든지 변경 될 수 있기 때문입니다 (NTP, DST 전환, 윤초 및 기타 여러 이유로 인해). 대신 mach_absolute_time을 사용하십시오.
nevyn

@nevyn 방금 내 인터넷 속도 테스트를 저장했습니다. 젠장, 복사 붙여 넣기 전에 주석을 읽어서 기뻐요 heh
Albert Renshaw

41

mach_absolute_time() 정확한 측정을 위해 사용할 수 있습니다.

참조 http://developer.apple.com/qa/qa2004/qa1398.html를

또한 볼 수 있습니다 CACurrentMediaTime()본질적으로 같은 일을하지만, 사용하기 쉬운 인터페이스이다.

(참고 :이 답변은 2009 년에 작성되었습니다. clock_gettime()최신 버전의 macOS 및 iOS에서 사용할 수있는 더 간단한 POSIX 인터페이스에 대한 Pavel Alexeev의 답변을 참조하십시오 .)


1
이 코드는 이상한 변환입니다. 첫 번째 예제의 마지막 줄은 "return * (uint64_t *) & elapsedNano;"입니다. 왜 그냥 "return (uint64_t) elapsedNano"가 아닌가?
Tyler

8
코어 애니메이션 (QuartzCore.framework)도 편리한 방법을 제공하며, CACurrentMediaTime()그 변환 mach_absolute_time()직접적으로 double.
otto

1
@Tyler, elapsedNano유형 인 Nanoseconds일반 정수 유형하지 않은. UnsignedWide두 개의 32 비트 정수 필드가있는 구조체 인의 별칭입니다 . 원하는 UnsignedWideToUInt64()경우 캐스트 대신 사용할 수 있습니다 .
Ken Thomases 2013-08-24

CoreServices는 Mac 라이브러리 일뿐입니다. iOS에 동등한 기능이 있습니까?
mm24

1
@ mm24 iOS에서는 Core Animation에있는 CACurrentMediaTime ()을 사용합니다.
Kristopher Johnson

28

사용하지 마십시오 NSDate, CFAbsoluteTimeGetCurrent또는 gettimeofday경과 시간을 측정 할 수 있습니다. 이들은 모두 시스템 시계에 의존하며, 이는 네트워크 시간 동기화 (NTP) 시계 업데이트 (드리프트를 조정하기 위해 자주 발생 함), DST 조정, 윤초 등과 같은 다양한 이유로 인해 언제든지 변경 될 수 있습니다 .

즉, 다운로드 또는 업로드 속도를 측정하는 경우 실제로 발생한 일과 관련이없는 수치가 갑자기 급증하거나 감소하게됩니다. 성능 테스트에는 이상하게 잘못된 이상 값이 있습니다. 잘못된 기간이 지나면 수동 타이머가 트리거됩니다. 시간은 뒤로 갈 수도 있고 음의 델타로 끝날 수 있으며 무한 재귀 또는 데드 코드로 끝날 수 있습니다 (예,이 두 가지를 모두 수행했습니다).

사용 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()QuartzCore에서?
Cœur

1
참고 : @import Darwin;대신 사용할 수도 있습니다#include <mach/mach_time.h>
Cœur

@ Cœur CACurrentMediaTime은 실제로 내 코드와 정확히 동일해야합니다. 좋은 찾기! (헤더는 "이것은 mach_absolute_time ()을 호출하고 단위를 초로 변환 한 결과입니다."라고 말합니다.)
nevyn

"네트워크 시간 동기화 (NTP) 시계 업데이트 (드리프트를 조정하기 위해 자주 발생), DST 조정, 윤초 등과 같은 다양한 이유로 인해 언제든지 변경 될 수 있습니다." -다른 이유는 무엇일까요? 인터넷에 연결되지 않은 상태에서 약 50ms의 뒤로 점프하는 것을 관찰하고 있습니다. 그래서, 분명히, 이러한 이유들 중 어느 것도 ... 적용 안
팔코

@Falko는 확실하지 않지만 추측해야한다면 다른 하드웨어 시계가 동기화되지 않은 것을 발견하면 OS가 자체적으로 드리프트 보상을 수행한다고 내기하겠습니다.
nevyn

14

CFAbsoluteTimeGetCurrent()A와 절대 시간 반환 double값을,하지만 난 정밀도가 무엇인지 모르는 -이 있습니다 매 수십 밀리 초를 업데이트하거나 모든 마이크로를, 나도 몰라 업데이트 할 수 있습니다.


2
그러나 배정 밀도 부동 소수점 값이며 밀리 초 미만의 정확도를 제공합니다. 72.89674947369 초 값은 드문 일이 아닙니다 ...
Jim Dovey

25
@JimDovey : 72.89674947369초 값은 다른 모든 값을 고려할 때 매우 드물다고 말해야 할 것입니다. ;)
FreeAsInBeer 2012

3
@Jim : 밀리 초 미만의 정확도를 제공한다는 인용이 있습니까 (정직한 질문입니다)? 여기있는 모든 사람들이 정확성과 정밀도 의 차이를 이해하기를 바랍니다 .
Adam Rosenfield 2012

5
CFAbsoluteTimeGetCurrent ()는 OS X에서 gettimeofday ()를 호출하고 Windows에서 GetSystemTimeAsFileTime ()을 호출합니다. 다음 은 소스 코드 입니다.
Jim Dovey

3
아, 그리고 gettimeofday ()는 mach_absolute_time ()을 통해 Mach 나노초 타이머를 사용하여 구현됩니다 . 다음은 Darwin / ARM에서 gettimeofday ()의 공통 페이지 구현에 대한 소스입니다. opensource.apple.com/source/Libc/Libc-763.12/arm/sys/…
Jim Dovey

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()a mach_timebase_info_data와 함께 사용 을 끝내고 (long double)((mach_absolute_time()*time_base.numer)/((1000*1000)*time_base.denom));. 마하 타임베이스를 얻으려면 할 수 있습니다(void)mach_timebase_info(&your_timebase);
Nate Symer

12
CFAbsoluteTimeGetCurrent () 문서에 따르면 "외부 시간 참조와의 동기화 또는 시계의 명시적인 사용자 변경으로 인해 시스템 시간이 감소 할 수 있습니다." 나는 왜 누군가가 거꾸로 갈 수 있다면 경과 시간을 측정하기 위해 이와 같은 것을 사용하려는 이유를 이해할 수 없습니다.
Kristopher Johnson 2013 년

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대신 정확한 경과 시간을 얻으려면 사용하십시오 .
Cœur

mach_absolute_time기기 재부팅의 영향을받을 수 있습니다. 대신 서버 시간을 사용하십시오.
kelin 2015

5

또한 NSNumberCoreData에 저장하려는 경우 Unix epoch (밀리 초)로 초기화 된 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

이게 낡은 거라는 건 알지만 다시 지나가는 나 자신을 발견했기 때문에 여기에 내 옵션을 제출할 것이라고 생각했습니다.

가장 좋은 방법은 내 블로그 게시물을 확인하는 것입니다. Objective-C : A stopwatch의 Timing things

기본적으로 저는 매우 기본적인 방식으로 시청을 중단하지만 캡슐화되어 다음 작업 만 수행하면되는 클래스를 작성했습니다.

[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대신 정확한 경과 시간을 얻으려면 사용하십시오 .
Cœur

1

NSDate를 사용하여 1970 년 1 월 1 일 이후 현재 시간을 밀리 초 단위로 가져올 수 있습니다.

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

이것은 밀리 초 단위로 시간을 제공하지만 여전히 초 정밀도
dev

-1

이를 위해 @Jeff Thompson의 답변의 Swift 버전이 필요합니다.

// 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대신 정확한 경과 시간을 얻으려면 사용하십시오 .
Cœur
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.