Rounding error in milliseconds using ISO8601FormatStyle instead of ISO8601DateFormatter

Hey there,

I was using the new ISO8601FormatStyle and using the includingFractionalSeconds option for it. But when decoding and encoding an iso8601 string, I do get rounding errors in the millisecond part.

I have setup a simple unit test:

import Testing
import UIKit

struct DateFormatterTests {
    @Test func testDateEncodingDecoding() async throws {
        let originalIsoString = "2024-10-05T17:08:34.650Z"
        
        let iso8601DateFormatter = ISO8601DateFormatter()
        iso8601DateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
        
        let testDate = iso8601DateFormatter.date(from: originalIsoString)!
        let oldFormatterString = iso8601DateFormatter.string(from: testDate)
        
        #expect(oldFormatterString == originalIsoString)
        
        let isoDateFormat: Date.ISO8601FormatStyle = .iso8601
            .year()
            .month()
            .day()
            .timeZone(separator: .omitted)
            .time(includingFractionalSeconds: true)
            .timeSeparator(.colon)
        
        let date = try isoDateFormat.parse(originalIsoString)
        
        let newFormatterString = isoDateFormat.format(date)
        
        #expect(newFormatterString == originalIsoString)
    }
}

This gives the following output:

✘ Test testDateEncodingDecoding() recorded an issue at DateFormatterTests.swift:35:9: Expectation failed: (newFormatterString → "2024-10-05T17:08:34.649Z") == (originalIsoString → "2024-10-05T17:08:34.650Z")

It has a rounding error in the new ISO8601FormatStyle of 1 ms.

Am I doing something fundamentally wrong here or is there something else at play? I probably has something to with date Date uses a floating type internally I guess?

EDIT:

I am using XCode Version 16.0 (16A242d)
Testing on my iPhone 12 Pro using iOS 18.0
I think it is still compiled with Swift 5 (Swift Language Version is set to Swift 5 as far as I can tell).

FWIW, the test passes ok for me (but I'm neither on the latest Xcode nor on the latest macOS version).

Thanks for the headsup, I am using:

XCode Version 16.0 (16A242d)
Testing on my iPhone 12 Pro using iOS 18.0
I think it is still compiled with Swift 5 (Swift Language Version is set to Swift 5 as far as I can tell).

It could be due to iOS 18, I am not sure, as bugs started showing up after I updated to iOS 18 on my device.

Yep, you're right. When tested against iOS 17.5 simulator it passes, when I test it against iOS 18.0 simulator it fails. So I guess this looks like a bug, although I don't know where?

This sounds like ISO8601FormatStyle produces unexpected results when including fractional seconds · Issue #963 · swiftlang/swift-foundation · GitHub

3 Likes