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"
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.