DateFormatter doesn't support time more precise than milliseconds, and smaller digits will be rounded to milliseconds.
Since DateComponents having a value of 999499997 or greater in nanosecond generates Date in which nanosecond is 999500036 or greater, DateFormatter rounds up and advances the result by 1 second.
POC:
import Foundation
let iso8601WithFractionalSecondFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSS'Z"
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter
}()
let gregorian = Calendar(identifier: .gregorian)
let utc = TimeZone(identifier: "UTC")!
let components = gregorian.dateComponents(in: utc, from: Date())
func check(from components: DateComponents, with nanosecond: Int) {
print("--")
print("Dircted nanosecond: \(nanosecond)")
var components = components
components.nanosecond = nanosecond
let date = components.date!
print("Actual nanosecond : \(gregorian.dateComponents(in: utc, from: date).nanosecond!)")
print("Date: \(iso8601WithFractionalSecondFormatter.string(from: date))")
}
check(from: components, with: 999499976)
check(from: components, with: 999499977)
Result:
--
Dircted nanosecond: 999499976
Actual nanosecond : 999499917
Date: 2019-06-25T14:35:36.999Z
--
Dircted nanosecond: 999499977
Actual nanosecond : 999500036
Date: 2019-06-25T14:35:37.000Z
We should drop nanosecond from Date before passing to DateFormatter when using nanosecond precision.
DateFormatterdoesn't support time more precise than milliseconds, and smaller digits will be rounded to milliseconds.Since
DateComponentshaving a value of 999499997 or greater innanosecondgeneratesDatein whichnanosecondis 999500036 or greater,DateFormatterrounds up and advances the result by 1 second.POC:
Result:
We should drop
nanosecondfromDatebefore passing toDateFormatterwhen using nanosecond precision.