ios - 使用 JSONDecoder 解码古怪的日期格式

标签 ios json swift nsdateformatter dateformatter

我在 JSON 返回中得到了以前从未见过的日期格式。

"/日期(965620800000-0400)/"

(现在是 Mon Aug 07 2000 00:00:00 GMT-0400)

这是一个以毫秒为单位的日期值,具有 GMT 偏移量。我正在尝试使用 Swift 的原生 JSONDecoder 并设置 dateDecodingStrategy

最初,我试过这个:

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

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

debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil)) The data couldn’t be read because it isn’t in the correct format.

我在 Unicode.org and found this 上搜索了一下,它表示 A 代表毫秒,Z 是带有小时、分钟和可选秒字段的 ISO8601 基本格式。

考虑到这一点,我做了一个 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: "Expected to decode Double but found a string/data instead.", underlyingError: nil)) The data couldn’t be read because it isn’t in the correct format.

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

最佳答案

您不能使用标准的 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 实例。

我将错误处理作为练习留给读者。

关于ios - 使用 JSONDecoder 解码古怪的日期格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49723780/

相关文章:

ios - UICollectionView 出列错误的单元格并显示错误的图像

ios - 一页上有多个 UITextFields 显示日期,但只有一个 UITextFields 显示从两个 DatePickers 中选择的日期

ios - xcode 4 编辑多个目标重复更改

ios - 里面有 TableView 的动态 Collection View 单元格?

c++ - 如何在 swift 项目中使用 c++ 库来制作更好的 glsl 编译器

java - Gson 反序列化 :Json Field Name Different from Java Object Field Name

ios - 如何让音乐在所有 View 中继续播放

ios - 实现另一个参数的 Swift 泛型类参数

sql - 如何用数据将数组更改为jsonb?

javascript - 从 Leaflet map 中删除 geoJSON