具有多种日期格式的 JSONDecoder?

Posted

技术标签:

【中文标题】具有多种日期格式的 JSONDecoder?【英文标题】:JSONDecoder with multiple date formats? 【发布时间】:2020-08-24 07:52:40 【问题描述】:

我有 2 种来自 api 的日期。我需要一起解码。但我没有找到任何解决方案。我需要在这段代码中添加"yyyy-MM-dd'T'HH:mm:ssZ" 格式。我该怎么做?

    func run<T: Decodable>(_ request: URLRequest, _ decoder: JSONDecoder = JSONDecoder()) -> AnyPublisher<Response<T>, Error> 
    return URLSession.shared
        .dataTaskPublisher(for: request)
        .receive(on: DispatchQueue.main)
        .tryMap  result -> Response<T> in
            self.dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
            decoder.dateDecodingStrategy = .formatted(self.dateFormatter)
            let value = try decoder.decode(T.self, from: result.data)
            return Response(value: value, response: result.response)
        
        .eraseToAnyPublisher()

【问题讨论】:

您能否澄清一下何时需要使用 format1 以及何时需要使用 format2?在同一个 JSON 中?在不同的?您是否确切知道它们在哪里使用,或者如果成功,您是否必须尝试?根据这一点,答案会有所不同。 func run 为我的所有项目工作。但只有一种不同的 json 结果(不同的结构)返回不同的时间格式。我不想为一个结果添加更多功能。 视情况而定。你有参数JSONDecoder = JSONDecoder(),我会把参数和它的dateFormatter放在这里,不会在trypMap()中覆盖它,或者只是在你的方法中添加一个DateFormatter参数。 我可以把它放在哪里?当我不把它放在这里时,这个日期的json返回空白。 各种可能的想法:pastebin.com/sZse166b 【参考方案1】:

另一种方法是自定义dateDecodingStrategyISO8601DateFormatter,它能够根据给定的字符串指定日期格式

func run<T: Decodable>(_ request: URLRequest, _ decoder: JSONDecoder = JSONDecoder()) -> AnyPublisher<Response<T>, Error> 
return URLSession.shared
    .dataTaskPublisher(for: request)
    .receive(on: DispatchQueue.main)
    .tryMap  result -> Response<T> in
        decoder.dateDecodingStrategy = .custom  decoder -> Date in
            let container = try decoder.singleValueContainer()
            let dateFormatter = ISO8601DateFormatter()
            let dateString = try container.decode(String.self)
            if !dateString.hasSuffix("Z")                             
                dateFormatter.formatOptions.remove(.withTimeZone) 
            
            if let isoDate = dateFormatter.date(from: dateString) 
                return isoDate 
             else 
                throw DecodingError.dataCorruptedError(in: container, debugDescription: "Wrong Date Format")
            
        
        let value = try decoder.decode(T.self, from: result.data)
        return Response(value: value, response: result.response)
    
    .eraseToAnyPublisher()

【讨论】:

谢谢它的工作,但这条线返回错误return dateFormatter.date(from: dateString) ?? throw DecodingError.dataCorruptedError(in: container, debugDescription: "Wrong Date Format")我这样使用return dateFormatter.date(from: dateString)! 我不会那样做,如果日期格式与两种格式不匹配会导致崩溃。请查看编辑。【参考方案2】:

您可以通过实现init(from decoder: Decoder)来实现自定义解码行为

https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types

【讨论】:

以上是关于具有多种日期格式的 JSONDecoder?的主要内容,如果未能解决你的问题,请参考以下文章

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

如何以这种日期格式使用 JSONDecoder / Codable?

如何处理 JSONDecoder 中的空日期字符串

导出具有指定日期格式的 Excel 工作表单元格

vba 转换多种格式日期

将包含多种字符串日期格式的列转换为 Spark 中的 DateTime