在JSONDecoder中,可以使用dateDecodingStrategy支持以下几种解码方法:
.iso8601: 使用ISO8601 解码策略
.deferredToDate:使用 Date 自身的编码/解码方法。
.secondsSince1970:将日期表示为自 1970 年 1 月 1 日 00:00:00 UTC 以来的秒数。
.millisecondsSince1970:将日期表示为自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数。
.formatted(formatter):使用自定义的 DateFormatter 来解析日期。
假设需要解码ISO 8601标准的日期:当返回的JSON日期格式符合ISO 8601 标准,可以直接使用 JSONDecoder 的内置策略。
使用内置策略解码时间
解决方案为,在解码时配置dateDecodingStrategy:
do {
let (data, _) = try await URLSession.shared.data(from: url)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601 // 使用 ISO8601 解码策略
return try decoder.decode([Friendface].self, from: data)
} catch {
print("Error decoding data: \(error)")
return nil
}
同时,将符合ISO 8601 标准字段修改为Date类型:
class Friendface: Codable, Hashable {
...
var registered: Date // 修改为 Date 类型
}
在显示视图新增formatDate函数:
func formatDate(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
formatter.timeZone = TimeZone.current // 设置为本地时区
return formatter.string(from: date)
}
这个函数规定了显示的日期格式。
在视图中使用formatDate函数显示时间:
Section("registered") {
Text("\(formatDate(friend?.registered ?? Date()))")
}
最后的显示效果为:

自定义日期解析器
除了使用内置策略解码时间,还可以自定义 DateDecodingStrategy 并结合 DateFormatter 处理时间。
首先确保符合ISO 8601 标准字段为Date类型:
var registered: Date // 修改为 Date 类型
使用JSONDecoder进行解码时,配置解码策略:
do {
let (data, _) = try await URLSession.shared.data(from: url)
let decoder = JSONDecoder()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" // 根据数据格式
decoder.dateDecodingStrategy = .formatted(dateFormatter)
return try decoder.decode([Friendface].self, from: data)
} catch {
print("Error decoding data: \(error)")
return nil
}
数据格式规定了显示的日期格式,注意dateFormat的格式为:
yyyy-MM-dd HH:mm:ssZ
尾部后面需要添加Z,这是因为这种格式是一种标准的日期时间格式,通常用于解析或生成符合 ISO 8601 标准的日期字符串。
固定字符 ‘T’,用于分隔日期和时间。
在 ISO 8601 格式中,日期和时间之间通常由 ‘T’ 分隔,例如:2024-11-10T13:45:30Z。
Z 是 “Zulu time” 的简写,表示 UTC时间。
在显示视图部分,和内置策略解码时间一样:
新增formatDate函数:
func formatDate(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
formatter.timeZone = TimeZone.current // 设置为本地时区
return formatter.string(from: date)
}
这个函数规定了显示的日期格式。
在视图中使用formatDate函数显示时间:
Section("registered") {
Text("\(formatDate(friend?.registered ?? Date()))")
}
带有毫秒的ISO8601格式
在使用dateDecodingStrategy的过程中,可能存在无法解码ISO8601格式的情况:
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
如果使用DecodingError就会看到如下报错:
---4---
Data corrupted: Expected date string to be ISO8601-formatted.
codingPath: [_CodingKey(stringValue: "Index 0", intValue: 0)]
报错说明:在 JSON 解码过程中,第一个元素(Index 0)中的某个字段被指定为 Date 类型,但它的字符串格式并不是 ISO8601 格式,导致解码失败。
如果JSON的日期字段为ISO8601格式,但是带了毫秒.000Z导致的报错。因为虽然大多数系统能识别带有毫米的格式,Swift默认的 .iso8601 并不能正确解析这种格式,所以会得到 dataCorrupted 错误。
针对带有毫米的ISO8601格式,需要使用DateFormatter:
let decoder = JSONDecoder()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
formatter.locale = Locale(identifier: "en_US_POSIX")
decoder.dateDecodingStrategy = .formatted(formatter)
通过DateFormatter设置对应的日期格式,Swift就可以解析带有毫秒的ISO时间字符串。
总结
1、内置策略解码时间使用:
decoder.dateDecodingStrategy = .iso8601 // 使用 ISO8601 解码策略
配置JSONDecoder的日期解码策略为.ISO8601。
2、自定义的日期解码器使用:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" // 根据数据格式
decoder.dateDecodingStrategy = .formatted(dateFormatter)
在这里使用的是DateFormatter日期格式化,使用dateFormat设置了日期格式,然后将设置的DateFormatter作为JSONDecoder的日期解析策略。
两种解码方式都可以用于处理ISO 8601标准格式解析日期。