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

RamwiseMatt picture RamwiseMatt · Jun 21, 2017 · Viewed 12.4k times · Source

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?

Answer

Leszek Zarna picture Leszek Zarna · Sep 15, 2017

Please try decoder configurated similarly to this:

lazy var decoder: JSONDecoder = {
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
        let container = try decoder.singleValueContainer()
        let dateStr = try container.decode(String.self)
        // possible date strings: "2016-05-01",  "2016-07-04T17:37:21.119229Z", "2018-05-20T15:00:00Z"
        let len = dateStr.count
        var date: Date? = nil
        if len == 10 {
            date = dateNoTimeFormatter.date(from: dateStr)
        } else if len == 20 {
            date = isoDateFormatter.date(from: dateStr)
        } else {
            date = self.serverFullDateFormatter.date(from: dateStr)
        }
        guard let date_ = date else {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "Cannot decode date string \(dateStr)")
        }
        print("DATE DECODER \(dateStr) to \(date_)")
        return date_
    })
    return decoder
}()