iosswiftnsdateformatter

Swift DateFormatter Optional Milliseconds


I have the following code to parse an ISO8601 date.

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"

Problem is sometimes the date is in a format like 2018-01-21T20:11:20.057Z, and other times it's in a format like 2018-01-21T20:11:20Z.

So basically part of the time it has the .SSS millisecond part, and other times it does not.

How can I setup the date formatter to make that part optional?

Edit

I forgot to mention a few details tho in my question I just realized. So I'm using the JSON Codable feature in Swift 4. So it just throws an error if it fails.

So I basically have the following code.

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(isoMilisecondDateFormatter())

return try decoder.decode([Person].self, from: _people)

An example JSON object for _people is the following.

[
    {
        "name": "Bob",
        "born": "2018-01-21T20:11:20.057Z"
    },
    {
        "name": "Matt",
        "born": "2018-01-21T20:11:20Z"
    }
]

The API I'm working with is pretty inconsistent so I have to deal with multiple types of data.


Solution

  • Two suggestions:

    Or in Swift 5.7+

        dateString.replace(/\.\d+/, with: "")
    

    Edit:

    To use it with Codable you have to write a custom initializer, specifying dateDecodingStrategy does not work

    struct Foo: Decodable {
        let birthDate : Date
        let name : String
        
        private enum CodingKeys : String, CodingKey { case born, name }
        
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            var rawDate = try container.decode(String.self, forKey: .born)
            rawDate.replace(/\.\d+/, with: "")
            birthDate = ISO8601DateFormatter().date(from: rawDate)!
            name = try container.decode(String.self, forKey: .name)
        }
    }
    

    let jsonString = """
    [{"name": "Bob", "born": "2018-01-21T20:11:20.057Z"}, {"name": "Matt", "born": "2018-01-21T20:11:20Z"}]
    """
    
    do {
        let data = Data(jsonString.utf8)
        let result = try JSONDecoder().decode([Foo].self, from: data)
        print(result)
    } catch {
        print("error: ", error)
    }