我需要什么样的数据模型来解码这种 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
}
首先,不要将您的自定义类型命名为
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
这是关于您选择的名称,您始终必须选择不同的名称。 您可以使用此代码访问和使用数据:
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
}
获取数据后,您可以将字符串格式化为日期