Swift将ISO8601格式字符串转Date并输出time ago相对时间方案
问题根因
转换返回nil由两个配置错误导致:
- 格式字符串不匹配:API返回的
2021-07-07T15:03:21.409Z为带毫秒的ISO8601标准UTC时间,原配置的yyyy-MM-dd HH:mm:ss缺少T分隔符、.SSS毫秒位、Z时区标识的匹配规则 - 时区配置错误:时间后缀的
Z代表UTC时区,原代码强制设置为巴黎时区,时区不匹配导致解析失败 - 附加隐性问题:原代码使用了系统默认locale,当用户系统语言为非拉丁语系时可能出现解析失败的兼容问题
修复代码
直接替换String扩展即可,也可保留通用转换方法适配其他场景:
extension String { // 专门适配当前API返回的ISO8601格式时间 func toISO8601Date() -> Date? { let dateFormatter = DateFormatter() // 固定locale为en_US_POSIX避免系统语言影响解析 dateFormatter.locale = Locale(identifier: "en_US_POSIX") // 对应Z标识的UTC时区 dateFormatter.timeZone = TimeZone(secondsFromGMT: 0) dateFormatter.calendar = Calendar(identifier: .gregorian) // 完全匹配API返回格式的格式串 dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" return dateFormatter.date(from: self) } }
- 补充优化:如果App最低支持iOS 10+/macOS 10.12+,更推荐使用系统自带的ISO8601解析器,无需手动维护格式串,兼容性更强:
extension String { func toISO8601Date() -> Date? { let formatter = ISO8601DateFormatter() formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] return formatter.date(from: self) } }
完整转换流程
修复后即可直接调用原有相对时间转换方法,完成完整流程:
// 示例API返回的时间字符串 let createTimeStr = "2021-07-07T15:03:21.409Z" // 第一步:字符串转Date guard let createDate = createTimeStr.toISO8601Date() else { // 此处添加解析失败的兜底逻辑,比如展示原始时间字符串 return } // 第二步:Date转相对时间字符串 let displayTime = createDate.timeAgoDisplay() // 可直接使用displayTime做UI展示
你原有提供的timeAgoDisplay扩展无需修改,Date解析正确后即可正常输出相对时间。
内容的提问来源于stack exchange,提问作者Mathieu Rios
相关产品推荐
相关产品推荐

