使用JSONDecoder

时间:2018-04-08 23:25:11

标签: ios json swift nsdateformatter dateformatter

我获得了以前在JSON回归中看不到的日期格式。

"/Date(965620800000-0400)/"

(它是Mon Aug 07 2000 00:00:00 GMT-0400

这是一个以GMT偏移量为单位的日期值(以毫秒为单位)。我试图使用Swift的原生JSONDecoder并设置dateDecodingStrategy

最初,我试过这个:

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

正如我最初所怀疑的那样,由于额外的非数字字符,它无法正常工作。这是我得到的最初错误:

  

debugDescription:"预计解码Double但找到一个字符串/数据   相反。",underlyingError:nil))无法读取数据,因为它   格式不正确。

我在Unicode.org and found this上挖掘,其中A表示毫秒,而Z是ISO8601基本forrmat,包含小时,分钟和可选秒字段。

考虑到这一点,我做了一个DateFormatter扩展名:

extension DateFormatter {
    static let nhtsaFormat: DateFormatter = {
        let formatter = DateFormatter()

        // This is the string that comes back --> "/Date(965620800000-0400)/"

        // These are the formats I tried:
        formatter.dateFormat = "'/Date('AZ')/'"
        // formatter.dateFormat = "'/Date('A')/'"
        // formatter.dateFormat = "'/Date('A`-`Z')/'"
        // formatter.dateFormat = "'/Date('A'-'Z')/'"
        // formatter.locale = Locale(identifier: "en_US_POSIX")
        return formatter
    }()
}

在我的DataManager课程上,我将decoder.dateDecodingStrategy更改为我的自定义格式,如下所示:

decoder.dateDecodingStrategy = .formatted(.nhtsaFormat)

对于各种格式,我仍然会收到此错误:

  

debugDescription:"预计解码Double但找到一个字符串/数据   相反。",underlyingError:nil))无法读取数据,因为它   格式不正确。

我尝试从我的Codable结构中删除有问题的日期键,我得到正确的回报,但不幸的是,我也需要日期。任何建议我如何解码该字符串非常感谢。

1 个答案:

答案 0 :(得分:2)

您无法使用标准DateFormatter解析此类日期字符串,因为没有标准格式说明符表示“自纪元以来的秒数(或毫秒数)”。 A格式说明符用于“一天中的秒数”。

一种解决方案是使用.custom日期解码策略和可以解析此类字符串的自定义方法。

以下是一些有效的测试代码:

func customDateParser(_ decoder: Decoder) throws -> Date {
    let dateString = try decoder.singleValueContainer().decode(String.self)
    let scanner = Scanner(string: dateString)
    var millis: Int64 = 0
    if scanner.scanString("/Date(", into: nil) &&
       scanner.scanInt64(&millis) &&
       scanner.scanInt(nil) &&
       scanner.scanString(")/", into: nil) &&
       scanner.isAtEnd {
        return Date(timeIntervalSince1970: TimeInterval(millis) / 1000)
    } else {
        return Date() // TODO - unexpected format, throw error
    }
}

let json = "{ \"date\": \"/Date(965620800000-0400)/\" }".data(using: .utf8)!

struct Test: Decodable {
    var date: Date
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom(customDateParser)
let test = try! decoder.decode(Test.self, from: json)
print(test)

请注意,日期字符串中的时区偏移量无关紧要。生成正确的Date实例不需要它。

我已将错误处理作为读者的练习。