Iso8601 date json decoding using swift4

So, I have iso8601 dates in my json that look like "2016-06-07T17: 20: 00.000 + 02: 00"

Is there a way to parse these iso8601 dates using swift4? Am I missing something?

I tried the following, but only the dateString "2016-06-07T17: 20: 00Z" from jsonShipA is legible ....

import Foundation

struct Spaceship : Codable {
    var name: String
    var createdAt: Date
}

let jsonShipA = """
{
    "name": "Skyhopper",
    "createdAt": "2016-06-07T17:20:00Z"
}
"""

let jsonShipB = """
{
    "name": "Skyhopper",
    "createdAt": "2016-06-07T17:20:00.000+02:00"
}
"""

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601

let dataA = jsonShipA.data(using: .utf8)!
if let decodedShip = try? decoder.decode(Spaceship.self, from: dataA) {
    print("jsonShipA date = \(decodedShip.createdAt)")
} else {
    print("Failed to decode iso8601 date format from jsonShipA")
}

let dataB = jsonShipB.data(using: .utf8)!
if let decodedShip = try? decoder.decode(Spaceship.self, from: dataB) {
    print("jsonShipA date = \(decodedShip.createdAt)")
} else {
    print("Failed to decode iso8601 date format from jsonShipB")
}

Playground Output:

jsonShipA date = 2016-06-07 17:20:00 +0000
Failed to decode iso8601 date format from jsonShipB

Error message: "The expected date string should be formatted in ISO8601 format." But as far as I know, the date "2016-06-07T17: 20: 00.000 + 02: 00" is a valid ISO8601 date

+4
source share
2 answers

You can use the following:

enum DateError: String, Error {
    case invalidDate
}

struct Spaceship : Codable {
    var name: String
    var createdAt: Date
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
    let container = try decoder.singleValueContainer()
    let dateStr = try container.decode(String.self)

    let formatter = DateFormatter()
    formatter.calendar = Calendar(identifier: .iso8601)
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
    if let date = formatter.date(from: dateStr) {
        return date
    }
    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX"
    if let date = formatter.date(from: dateStr) {
        return date
    }
    throw DateError.invalidDate
})
+12
source

TL; DR : withInternetDateTime ISO8601DateFormatter . , .

:

Swift 787, :

/// Decode the `Date` as an ISO-8601-formatted string (in RFC 3339 format).

RFC, ( , ) 5.8:

1985-04-12T23:20:50.52Z
1996-12-19T16:39:57-08:00
1996-12-20T00:39:57Z
1990-12-31T23:59:60Z
1990-12-31T15:59:60-08:00
1937-01-01T12:00:27.87+00:20

Swift, . , , . , Swift, , Foundation ISO8601DateFormatter.

Swift unittest , . 180. . , , , , ISO8601DateFormatter, .withInternetDateTime, .

+11

Source: https://habr.com/ru/post/1686786/


All Articles