ISO8601DateFormatter fails to parse a valid ISO-8601 date

This works with or without milliseconds because it ignores the time portion of the string. That is, your resulting Date will always have time at 00:00:00Z.

Adding .withFullTime brings us back to matching either with or without milliseconds again.

1 Like

Im having the same issue and i've solved it the same way as above. Im curious though what backend apis are written in in these cases. They are all .net backend apis i bet. that's what i've seen the most non standard stuff with.

any updates on this?

Only hope to get this fixed is to ensure the swift-foundation rewrite increases compatibility. I don't think they've implemented DateFormatter publicly yet but some of the tools are there, so hopefully we can see the implementation before it goes public.

I made a ticket on the swift foundation github to get some attention to this.

Hopefully we get a fix for it there at the very least.

I want to throw in some other specifity:
As far as I understood "date only" (without time) is also ISO/RFC compliant.
The ISO decoding strategy cannot handle this case either.

Some services don't want to represent time in a date and represent dates using the ISO format, but Swift can't handle that without modifications.

Apparently the standard is much more generic than just one type of string representation in JSON, so I think the name "iso8601" for the decoding stategy is too generic.

We should have different strict formats for "iso8601" and also lenient variants.

1 Like

In case this is useful to anyone else: I was led to revisit this because I'd been using a JSONDecoder with

let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = [
    .withInternetDateTime, .withFractionalSeconds
]

decoder.dateDecodingStrategy = .custom({ decoder in
     // Error handling omitted for brevity
    dateFormatter.date(from: try! decoder.singleValueContainer().decode(String.self))!
})

but Swift 6 is warning that ISO8601DateFormatter is not Sendable, which is a requirement of the .custom closure.

I noticed that Foundation's internal handling for the .iso8601 strategy is effectively just Date.ISO8601FormatStyle().parse(string)

... which led me to realize I could use a custom Date.ISO8601FormatStyle to have a simpler (and probably faster?) alternative that is free from Sendable violations:

decoder.dateDecodingStrategy = .custom({ decoder in
    // Again skipping error handling for brevity
    let string = try! decoder.singleValueContainer().decode(String.self)
    return try! Date.ISO8601FormatStyle(includingFractionalSeconds: true).parse(string)
})

It would still be cleaner and more discoverable to have a .iso8601WithOptions(...) strategy like @itaiferber proposed, but in the absence of that this is functionally equivalent.