Skip to content

YAMLEncoder outputs a result that is delayed by 1 second when encoding Date with nanoseconds greater than 999499997 #192

@norio-nomura

Description

@norio-nomura

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions