0

I am implementing a timer that requires calculating the milliseconds of the user being inactive and calculate the difference and recover the timer. Since there is no milliseconds option in dateComponents, I used nanoseconds instead, however, when I try to calculate the nanoseconds interval between two dates, I get the same results every time (current date is changing, should get different result), if I change the nanosecond to second, it works. I executed it twice to experiment.

let d1 = Date()
let df = DateFormatter()
df.dateFormat = "y-MM-dd H:m:ss.SSSS"
let d2 = df.date(from: "2021-05-03 9:30:00.1234")!

print(df.string(from: d1)) 
print(df.string(from: d2)) 
print(Calendar.current.dateComponents([.second], from: d1, to: d2).second!) 
// result1: "85573"
// result2: "85067"

When I use nanosecond

let d1 = Date()
let df = DateFormatter()
df.dateFormat = "y-MM-dd H:m:ss.SSSS"
let d2 = df.date(from: "2021-05-03 9:30:00.1234")!

print(df.string(from: d1))
print(df.string(from: d2))
print(Calendar.current.dateComponents([.nanosecond], from: d1, to: d2).nanosecond!)
// result1: "2147483647"
// result2: "2147483647"
0

2 Answers 2

4

Although I cannot find it documented: It seems that the possible values of all date components are limited to those of a signed 32-bit integer, and values outside of that range are truncated to Int32.max = 2147483647 or Int32.min = -2147483648:

let d1 = Date()
let d2 = d1.addingTimeInterval(2)
print(Calendar.current.dateComponents([.nanosecond], from: d1, to: d2).nanosecond!)
// 2000000000
let d3 = d1.addingTimeInterval(3)
print(Calendar.current.dateComponents([.nanosecond], from: d1, to: d3).nanosecond!)
// 2147483647
let d4 = d1.addingTimeInterval(-3)
print(Calendar.current.dateComponents([.nanosecond], from: d1, to: d4).nanosecond!)
// -2147483648

If you request both seconds and nanoseconds, then the nanosecond component holds only the fractional seconds, which makes your code produce correct results again:

print(Calendar.current.dateComponents([.second, .nanosecond], from: d1, to: d2))
// Example output:
// second: 111403 nanosecond: 464950927 isLeapMonth: false

If you just need the difference between the two points in time in milliseconds, then

let elapsed = Int(d2.timeIntervalSince(d1) * 1000)

is a simpler option.

Sign up to request clarification or add additional context in comments.

Comments

2

No need for all the date component stuff. Just subtract one date from another using timeIntervalSinceReferenceDate on each one. Or:

https://developer.apple.com/documentation/foundation/date/3329238-distance

The result is in seconds with accuracy to milliseconds so multiply by 1000 and you’re done.

2 Comments

Just mentioning that there is no difference between distance(to:) and timeIntervalSince(_:): github.com/apple/swift-corelibs-foundation/blob/main/Sources/…. – For some reason Date defines a Stride and all methods required for the Strideable protocol, but does not conform to that protocol.
@MartinR Word on the street is they’re sorry about that Stridable foray and distance could be retracted. I’m a little nervous about recommending it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.