如何获得精确的时间,例如在 Objective-C 中以毫秒为单位?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/889380/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 21:35:09  来源:igfitidea点击:

How can I get a precise time, for example in milliseconds in Objective-C?

iphoneobjective-ccocoa-touchuikit

提问by Thanks

Is there an easy way to get a time very precisely?

有没有一种简单的方法可以非常精确地获取时间?

I need to calculate some delays between method calls. More specifically, I want to calculate the speed of scrolling in an UIScrollView.

我需要计算方法调用之间的一些延迟。更具体地说,我想计算 UIScrollView 中的滚动速度。

回答by Jeff Thompson

NSDateand the timeIntervalSince*methods will return a NSTimeIntervalwhich is a double with sub-millisecond accuracy. NSTimeIntervalis in seconds, but it uses the double to give you greater precision.

NSDate并且这些timeIntervalSince*方法将返回一个NSTimeInterval具有亚毫秒精度的双精度值。NSTimeInterval以秒为单位,但它使用双精度来为您提供更高的精度。

In order to calculate millisecond time accuracy, you can do:

为了计算毫秒时间精度,您可以执行以下操作:

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

Documentation on timeIntervalSinceNow.

关于 timeIntervalSinceNow 的文档

There are many other ways to calculate this interval using NSDate, and I would recommend looking at the class documentation for NSDatewhich is found in NSDate Class Reference.

还有许多其他方法可以使用 计算此间隔NSDate,我建议您查看NSDate 类参考NSDate中的类文档

回答by Kristopher Johnson

mach_absolute_time()can be used to get precise measurements.

mach_absolute_time()可用于获得精确的测量值。

See http://developer.apple.com/qa/qa2004/qa1398.html

http://developer.apple.com/qa/qa2004/qa1398.html

Also available is CACurrentMediaTime(), which is essentially the same thing but with an easier-to-use interface.

也可用的是CACurrentMediaTime(),它本质上是相同的,但具有更易于使用的界面。

回答by nevyn

Please do not use NSDate, CFAbsoluteTimeGetCurrent, or gettimeofdayto measure elapsed time. These all depend on the system clock, which can change at anytime due to many different reasons, such as network time sync (NTP) updating the clock (happens often to adjust for drift), DST adjustments, leap seconds, and so on.

请不要使用NSDateCFAbsoluteTimeGetCurrent、 或gettimeofday来测量经过的时间。这些都依赖于系统时钟,它可以在改变任何时间,由于许多不同的原因,诸如网络时间同步(NTP)更新时钟(经常发生以调整漂移),DST调整,闰秒,等等。

This means that if you're measuring your download or upload speed, you will get sudden spikes or drops in your numbers that don't correlate with what actually happened; your performance tests will have weird incorrect outliers; and your manual timers will trigger after incorrect durations. Time might even go backwards, and you end up with negative deltas, and you can end up with infinite recursion or dead code (yeah, I've done both of these).

这意味着,如果您正在测量下载或上传速度,您的数字会突然激增或下降,这与实际发生的情况无关;你的性能测试会有奇怪的不正确的异常值;并且您的手动计时器将在不正确的持续时间后触发。时间甚至可能倒流,最终会出现负增量,并且最终可能会出现无限递归或死代码(是的,我已经完成了这两件事)。

Use mach_absolute_time. It measures real seconds since the kernel was booted. It is monotonically increasing (will never go backwards), and is unaffected by date and time settings. Since it's a pain to work with, here's a simple wrapper that gives you NSTimeIntervals:

使用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

回答by Adam Rosenfield

CFAbsoluteTimeGetCurrent()returns the absolute time as a doublevalue, but I don't know what its precision is -- it mightonly update every dozen milliseconds, or it might update every microsecond, I don't know.

CFAbsoluteTimeGetCurrent()将绝对时间作为一个double值返回,但我不知道它的精度是多少——它可能只每几十毫秒更新一次,或者它可能每微秒更新一次,我不知道。

回答by Nate Symer

I would NOT use mach_absolute_time()because it queries a combination of the kernel and the processor for an absolute time using ticks (probably an uptime).

我不会使用,mach_absolute_time()因为它使用滴答(可能是正常运行时间)在绝对时间内查询内核和处理器的组合。

What I would use:

我会用什么:

CFAbsoluteTimeGetCurrent();

This function is optimized to correct the difference in the iOS and OSX software and hardware.

此功能经过优化,可纠正 iOS 和 OSX 软件和硬件的差异。

Something Geekier

更极客的东西

The quotient of a difference in mach_absolute_time()and AFAbsoluteTimeGetCurrent()is always around 24000011.154871

在差的商mach_absolute_time()AFAbsoluteTimeGetCurrent()始终围绕24000011.154871

Here is a log of my app:

这是我的应用程序的日志:

Please note that final result time is a difference in CFAbsoluteTimeGetCurrent()'s

请注意,最后的结果是时间的差别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] -----------------------------------------------------

回答by gngrwzrd

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

Usage:

用法:

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

Output:

输出:

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

回答by John Wright

Also, here is how to calculate a 64-bit NSNumberinitialized with the Unix epoch in milliseconds, in case that is how you want to store it in CoreData. I needed this for my app which interacts with a system that stores dates this way.

此外,这里是如何以NSNumber毫秒为单位计算使用 Unix 纪元初始化的 64 位,以防您希望将其存储在 CoreData 中。我的应用程序需要这个,它与以这种方式存储日期的系统交互。

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

回答by Pavel Alexeev

Functions based on mach_absolute_timeare good for short measurements.
But for long measurements important caveat is that they stop ticking while device is asleep.

基于的函数适用于mach_absolute_time短期测量。
但是对于长时间的测量,重要的警告是当设备处于睡眠状态时它们会停止滴答作响。

There is a function to get time since boot. It doesn't stop while sleeping. Also, gettimeofdayis not monotonic, but in my experiments I've always see that boot time changes when system time changes, so I think it should work fine.

有一个功能可以获取自启动以来的时间。它不会在睡觉时停止。此外,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
}

And since iOS 10 and macOS 10.12 we can use CLOCK_MONOTONIC:

从 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
    }
}

To sum it up:

把它们加起来:

  • Date.timeIntervalSinceReferenceDate— changes when system time changes, not monotonic
  • CFAbsoluteTimeGetCurrent()— not monotonic, may go backward
  • CACurrentMediaTime()— stops ticking when device is asleep
  • timeSinceBoot()— doesn't sleep, but might be not monotonic
  • CLOCK_MONOTONIC— doesn't sleep, monotonic, supported since iOS 10
  • Date.timeIntervalSinceReferenceDate— 随系统时间变化而变化,而不是单调的
  • CFAbsoluteTimeGetCurrent()— 不单调,可能会倒退
  • CACurrentMediaTime()- 当设备处于睡眠状态时停止滴答
  • timeSinceBoot()— 不睡觉,但可能不是单调的
  • CLOCK_MONOTONIC— 不休眠,单调,自 iOS 10 起支持

回答by Camilo Ortegón

You can get current time in milliseconds since January 1st, 1970 using an NSDate:

您可以使用 NSDate 以毫秒为单位获取自 1970 年 1 月 1 日以来的当前时间:

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

回答by bladnman

I know this is an old one but even I found myself wandering past it again, so I thought I'd submit my own option here.

我知道这是一个旧的,但即使我发现自己又一次徘徊过去,所以我想我会在这里提交我自己的选择。

Best bet is to check out my blog post on this: Timing things in Objective-C: A stopwatch

最好的办法是查看我的博客文章: Objective-C 中的计时:秒表

Basically, I wrote a class that does stop watching in a very basic way but is encapsulated so that you only need to do the following:

基本上,我编写了一个以非常基本的方式停止观看但被封装的类,因此您只需要执行以下操作:

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

And you end up with:

你最终得到:

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

in the log...

在日志...

Again, check out my post for a little more or download it here: MMStopwatch.zip

再次,查看我的帖子了解更多信息或在此处下载: MMStopwatch.zip