Can't decode date in Swift 4
It looks like one of your birthdates:
"birthdate": "2009-05-06T18:56:38.367",
contains milliseconds. Your date format string:
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
Isn't able to handle this. You can either change the birthdate
field in the incoming JSON, or change your dateFormat
string to this:
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
Note that adding .SSS
appears to break the formatter for non-millisecond dates. I'd recommend cutting out the milliseconds server-side.
Original answer below:
I've just tried this in a Playground, and it appears to work as expected:
class Person : Codable {
var birthdate: Date = Date()
var firstName: String = ""
var lastName: String = ""
enum CodingKeys : String, CodingKey {
case birthdate
case firstName = "first_name"
case lastName = "last_name"
}
}
var json: String = """
[
{
"birthdate": "2009-05-06T18:56:38",
"first_name": "John",
"last_name": "Smith"
}
]
"""
let decoder = JSONDecoder()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let people = try! decoder.decode(Array<Person>.self, from: json.data(using: .utf8, allowLossyConversion: false)!)
Where people
is now this:
{birthdate "May 6, 2009 at 6:56 PM", firstName "John", lastName "Smith"}
Either there's something subtly different between my code and yours, or there may be a different set of example data needed.
You just forgot to add milliseconds to your date format.
Change this line:
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
.
With this:
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
If you decode JSON with dates in multiple parts of your code I recommend doing a custom class to adapt the decoding to what you need in this case: decoding Date.
The implementation will be something like this:
/**Custom decoder for dates*/
class DecoderDates: JSONDecoder {
override func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable {
let decoder = JSONDecoder()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
decoder.dateDecodingStrategy = .formatted(dateFormatter)
return try decoder.decode(T.self, from: data)
}
}
Example use:
DecoderDates().decode(Codable.self, from: data)
Hope this helps someone.