iso8601使用swift4解码日期json

P5y*_*cH0 12 swift swift4

所以,我的json中有iso8601日期,看起来像"2016-06-07T17:20:00.000 + 02:00"

有没有办法使用swift4解析这些iso8601日期?我错过了一些明显的东西吗

我尝试了以下,但只有来自jsonShipA的dateString"2016-06-07T17:20:00Z"是可解析的....

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")
}
Run Code Online (Sandbox Code Playgroud)

操场的输出是:

jsonShipA date = 2016-06-07 17:20:00 +0000
Failed to decode iso8601 date format from jsonShipB
Run Code Online (Sandbox Code Playgroud)

抛出的错误是"预期日期字符串为ISO8601格式".但据我所知,日期"2016-06-07T17:20:00.000 + 02:00"是有效的ISO8601日期

Vin*_*App 31

你可以像这样使用:

enum DateError: String, Error {
    case invalidDate
}

let decoder = JSONDecoder() 

let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)

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

    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
})
Run Code Online (Sandbox Code Playgroud)


Bar*_*uik 24

TL; DR版本:它只解析此处描述的ISO8601DateFormatter的withInternetDateTime格式.这意味着您的字符串不应该有毫秒.

更多信息:

看一下787行的Swift来源,评论说:

/// Decode the `Date` as an ISO-8601-formatted string (in RFC 3339 format).
Run Code Online (Sandbox Code Playgroud)

看看那个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
Run Code Online (Sandbox Code Playgroud)

只有第二个和第三个例子实际上是由Swift解码的,其余的都是失败的.在我看来,评论不正确,或实施不完整.至于真正的实现,那是在Swift源之外,它似乎只是在Foundation中使用ISO8601DateFormatter类.

斯威夫特单元测试也非常有限,看线180它只是编码一个日期,然后解码回.因此,换句话说,这是测试的唯一的事情,就是在默认情况下,它是硬编码的选项ISO8601DateFormatter输出格式.withInternetDateTime,这里描述.