Search code examples
swiftjson-deserializationcodable

Swift's JSONDecoder with multiple date formats in a JSON string?


Swift's JSONDecoder offers a dateDecodingStrategy property, which allows us to define how to interpret incoming date strings in accordance with a DateFormatter object.

However, I am currently working with an API that returns both date strings (yyyy-MM-dd) and datetime strings (yyyy-MM-dd HH:mm:ss), depending on the property. Is there a way to have the JSONDecoder handle this, since the provided DateFormatter object can only deal with a single dateFormat at a time?

One ham-handed solution is to rewrite the accompanying Decodable models to just accept strings as their properties and to provide public Date getter/setter variables, but that seems like a poor solution to me. Any thoughts?


Solution

  • There are a few ways to deal with this:

    • You can create a DateFormatter subclass which first attempts the date-time string format, then if it fails, attempts the plain date format
    • You can give a .custom Date decoding strategy wherein you ask the Decoder for a singleValueContainer(), decode a string, and pass it through whatever formatters you want before passing the parsed date out
    • You can create a wrapper around the Date type which provides a custom init(from:) and encode(to:) which does this (but this isn't really any better than a .custom strategy)
    • You can use plain strings, as you suggest
    • You can provide a custom init(from:) on all types which use these dates and attempt different things in there

    All in all, the first two methods are likely going to be the easiest and cleanest — you'll keep the default synthesized implementation of Codable everywhere without sacrificing type safety.