如何将日期 JSON 解码为 Swift 模型?

问题描述 投票:0回答:2

我需要什么样的数据模型来解码这种 json 日期格式?

示例 json:

{
    createdAt: "2021-01-30T22:48:00.469Z",
    updatedAt: "2021-01-30T22:48:00.490Z"
}

我尝试使用这个模型,但不断出现解码错误......

struct Date: Decodable {
    var createdAt: Date
    var updatedAt: Date   
}
ios json swift date decoding
2个回答
4
投票

首先,不要将您的自定义类型命名为

Date
- 它与标准库的
Date
冲突。我将其重命名为
DateInfo

struct DateInfo: Decodable {
   var createdAt: Date
   var updatedAt: Date   
}

然后,要将日期解码为

Date
,您需要设置dateDecodingStrategy
上的
JSONDecoder
来选择日期格式。在您的示例中,这是标准的 iso8601 格式,但带有小数秒,并且(感谢@LeoDabus)内置解码策略
.iso8601
不支持:

所以,没有小数秒,就会像这样完成:

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

let dateInfo = try decoder.decode(DateInfo.self, from: jsonData)

但是对于小数秒,需要一些手动工作来使用

ISO8601DateFormatter
进行解码和格式化。为了方便起见,我们可以使用自定义格式化程序和日期解码策略创建扩展:

extension Formatter {
   static var customISO8601DateFormatter: ISO8601DateFormatter = {
      let formatter = ISO8601DateFormatter()
      formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
      return formatter
   }()
}

extension JSONDecoder.DateDecodingStrategy {
   static var iso8601WithFractionalSeconds = custom { decoder in
      let dateStr = try decoder.singleValueContainer().decode(String.self)
      let customIsoFormatter = Formatter.customISO8601DateFormatter
      if let date = customIsoFormatter.date(from: dateStr) {
         return date
      }
      throw DecodingError.dataCorrupted(
               DecodingError.Context(codingPath: decoder.codingPath, 
                                     debugDescription: "Invalid date"))
   }
}

除了使用自定义策略外,用法与内置策略类似:

decoder.dateDecodingStrategy = .iso8601WithFractionalSeconds

-1
投票

这是关于您选择的名称,您始终必须选择不同的名称。 您可以使用此代码访问和使用数据:

struct AboutDate: Codable {
    let createdAt, updatedAt: String?
}


extension AboutDate {
    init(data: Data) throws {
        self = try newJSONDecoder().decode(AboutDate.self, from: data)
    }

    init(_ json: String, using encoding: String.Encoding = .utf8) throws {
        guard let data = json.data(using: encoding) else {
            throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
        }
        try self.init(data: data)
    }

    init(fromURL url: URL) throws {
        try self.init(data: try Data(contentsOf: url))
    }

    func with(
        createdAt: String?? = nil,
        updatedAt: String?? = nil
    ) -> AboutDate {
        return AboutDate(
            createdAt: createdAt ?? self.createdAt,
            updatedAt: updatedAt ?? self.updatedAt
        )
    }

    func jsonData() throws -> Data {
        return try newJSONEncoder().encode(self)
    }

    func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
        return String(data: try self.jsonData(), encoding: encoding)
    }
}

func newJSONDecoder() -> JSONDecoder {
    let decoder = JSONDecoder()
    if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
        decoder.dateDecodingStrategy = .iso8601
    }
    return decoder
}

func newJSONEncoder() -> JSONEncoder {
    let encoder = JSONEncoder()
    if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
        encoder.dateEncodingStrategy = .iso8601
    }
    return encoder
}

使用方法:

do {
   let aboutDate = try AboutDate(json)
}
catch {
   //handle err
}

获取数据后,您可以将字符串格式化为日期

© www.soinside.com 2019 - 2024. All rights reserved.