1

This snapshot of some Playground code shows my attempt to adjust an NSDate by nanoseconds, followed by trying to get the same value of nanoseconds by comparing the first NSDate with the second NSDate:

enter image description here

Given all the stuff about floating-point numbers and decimal inaccuracy, I can see that using NSTimeInterval may not be the way to do this.

Another possibility would be using NSDateComponents, I think. The whole process is really confusing to me though. It seems like you have to create a gregorian calender object, then get the nanoseconds into it from the NSDate somehow, then adjust the nanonseconds directly and get it all back into an NSDate again. Very complicated!

But since NSCalendar has a built-in way for storing nanoseconds as Ints I suppose I really need clarification on whether or not it can be used reliably for this purpose.

Le Mot Juiced
  • 3,761
  • 1
  • 26
  • 46
  • What's the point of calculating the nanosecond difference of two NSdate instances? According to Apple documentation on [NSDate](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/DatesAndTimes/Articles/dtDates.html), it's precise to milliseconds by its nature. Any more precise calculation on it is unuseful. – utogaria Aug 07 '15 at 16:32
  • @utogaria dispatch_time_t works in nanoseconds, so if you're trying to make use of Grand Central Dispatch with precision you need nanoseconds – Le Mot Juiced Aug 07 '15 at 16:45
  • @LeMotJuiced: NSDate also uses a NSTimeInterval to store its time value, so it does not make any difference which one you use, neither can represent nanoseconds precisely. You can use NSDateComponents or an UInt64 representing the nanoseconds. But as soon as you convert back to NSDate, the precision is lost. – Martin R Aug 07 '15 at 17:03
  • Perhaps you should read up on "floating-point numbers and decimal inaccuracy". It is not that floating-point numbers are not accurate just that many decimal (base 10) numbers can not be represented *exactly* as a binary (base 2) floating point number much the same way pi can not be represented exactly as a decimal (base 10) number but can be represented exactly as a pi (base pi) number. In the base pi number system the circumference of a circle is exactly 2. – zaph Aug 07 '15 at 17:13
  • @zaph I refer to floating-point inaccuracy in the question. It's the premise that made me look at NSDateComponents. – Le Mot Juiced Aug 07 '15 at 17:15
  • For a double the accuracy is slightly more than 15 decimal digits. – zaph Aug 07 '15 at 17:20
  • @MartinR Thanks, right on point. The question to me becomes, since the only way to make an NSDateComponents object is by using NSDate, where does NSDateComponents get the nanosecond data from? Does it use the NSTimeInterval directly, disregarding the fact that it's inaccurate? – Le Mot Juiced Aug 07 '15 at 17:20
  • @LeMotJuiced: Yes, I strongly assume so. The NSDate documentation states: *"The sole primitive method of NSDate, timeIntervalSinceReferenceDate, provides the basis for all the other methods in the NSDate interface. This method returns a time value relative to an absolute reference date—the first instant of 1 January 2001, GMT."* – Btw, this might also interest you: http://stackoverflow.com/questions/23684727/nsdateformatter-milliseconds-bug. It is a different question, but shows that NSCalendar uses the ICU Calendar which also has precision restrictions. – Martin R Aug 07 '15 at 17:25

1 Answers1

1

For very percise time use mach_absolute_time(). See Apple Q&A1398 for details.

Swift version from a SO answer by Martin R

let t1 = mach_absolute_time()
let t2 = mach_absolute_time()

let elapsed = t2 - t1
var timeBaseInfo = mach_timebase_info_data_t()
mach_timebase_info(&timeBaseInfo)
let elapsedNano = elapsed * UInt64(timeBaseInfo.numer) / UInt64(timeBaseInfo.denom);
println(elapsedNano)

Objective-C version:

#import <mach/mach_time.h>

mach_timebase_info_data_t info;
mach_timebase_info(&info);

uint64_t start = mach_absolute_time ();
uint64_t end = mach_absolute_time ();
uint64_t elapsed = end - start;

uint64_t nanos = elapsed * info.numer / info.denom;
NSLog(@"elasped: %llu nano seconds", nanos);

CGFloat seconds = (CGFloat)nanos / NSEC_PER_SEC;
NSLog(@"elasped: %0.9f seconds", seconds);

elasped: 45 nano seconds
elasped: 0.000000045 seconds

Community
  • 1
  • 1
zaph
  • 111,848
  • 21
  • 189
  • 228
  • 1
    You're right, that's a useful format, and I made a mistake in asking if there was another way without specifying that I need to stick with NSDate as a base. I've edited to correct this. In context of the app, I'm already using dispatch_time and NSDate for specific reasons and I'm loath to add a third time format with janky conversions. Since NSCalendar has a built-in way for storing nanoseconds as Ints I suppose I really need clarification on whether or not it can be used reliably for this purpose. Just edited post *again* for further clarity on this. – Le Mot Juiced Aug 07 '15 at 16:55