I'm currently trying to learn Swift and haven't gotten very far yet, so forgive me if this is an easy problem; I've been working on it for hours now and haven't been able to figure it out.
I have a Codable
class called Person
. On this class I have a Date
property called birthdate
. So it looks like this:
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"
}
}
And I'm trying to decode my JSON:
[
{
"address": "302 N. 5th St.",
"base_64_image": null,
"birthdate": "2009-05-06T18:56:38.367",
"created": "2017-11-21T16:21:13",
"emergency_contact": "",
"emergency_contact_number": null,
"father_cell_number": null,
"father_home_number": null,
"father_name": null,
"first_name": "John",
"gender": 1,
"id": "d92fac59-66b9-49a5-9446-005babed617a",
"image_uri": null,
"is_inactive": false,
"last_name": "Smith",
"mother_cell_number": "1234567890",
"mother_home_number": "",
"mother_name": "His Mother",
"nickname": null,
"tenant_id": "9518352f-4855-4699-b0da-ecdc06470342",
"updated": "2018-01-20T02:11:45.9025023"
}
]
like this:
// Fetch the data from the URL.
let headers: HTTPHeaders = [
"Accept": "application/json"
]
Alamofire.request(url, headers: headers).responseJSON { response in
if let data = response.data {
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: data)
}
}
However, I always get the same error:
Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 47", intValue: Optional(47)), App.Person.CodingKeys.birthdate], debugDescription: "Date string does not match format expected by formatter.", underlyingError: nil))
(The "Index 47" obviously isn't accurate, since that's for my live [and private] data).
If I take the birthdate
property off the Person
class everything works as expected.
I've been Googling and trying new things for several hours, and still can't get it to work no matter what I try. Can anyone here help me out?
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 love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With