如何使用Swift的JSONDecoder解析/Date(xxx-xxxx)/格式日期
解决Swift中解析"/Date(时间戳-偏移量)/"格式日期的问题
我之前也碰到过这种.NET风格的日期格式,确实挺让人头疼的!原生的JSONDecoder日期解码策略直接用.millisecondsSince1970肯定不行,因为这个格式里混了字符串和偏移量信息,咱们得自定义一个解码逻辑来搞定它。
核心思路
这种格式的结构是/Date(毫秒时间戳±GMT偏移量)/,咱们需要:
- 从字符串中提取出毫秒时间戳和时区偏移量
- 将偏移量转换为对应的
TimeZone - 用时间戳生成正确的
Date对象(注意Date本身是基于UTC的绝对时间,偏移量主要影响显示,解码时只要时间戳正确就没问题)
完整代码实现
直接给你能跑的代码,你可以直接集成到项目里:
// 初始化JSONDecoder并设置自定义日期解码策略 let decoder = JSONDecoder() decoder.dateDecodingStrategy = .custom { decoder in // 先把日期内容解码成字符串 let container = try decoder.singleValueContainer() let dateString = try container.decode(String.self) // 用正则匹配提取时间戳和偏移量 let datePattern = #"\/Date\((\d+)([+-]\d{4})\)\/"# guard let regex = try? NSRegularExpression(pattern: datePattern), let match = regex.firstMatch(in: dateString, range: NSRange(dateString.startIndex..., in: dateString)) else { throw DecodingError.dataCorruptedError( in: container, debugDescription: "无法解析日期格式: \(dateString)" ) } // 提取并转换毫秒时间戳 let timestampRange = Range(match.range(at: 1), in: dateString)! let timestampString = String(dateString[timestampRange]) guard let timestampMs = Double(timestampString) else { throw DecodingError.dataCorruptedError( in: container, debugDescription: "无效的时间戳: \(timestampString)" ) } let timestampSec = timestampMs / 1000 // 转成秒,适配Date的API // 提取并转换时区偏移量(比如-0400转成秒数) let offsetRange = Range(match.range(at: 2), in: dateString)! let offsetString = String(dateString[offsetRange]) let hours = Int(offsetString.prefix(3))! let minutes = Int(offsetString.suffix(2))! let offsetSeconds = hours * 3600 + minutes * 60 // 这里其实Date本身是UTC时间,时区主要影响后续显示,解码时可以不用特意调整,因为时间戳已经是对应UTC的正确值了 // 如果需要验证,你可以用这个时区来格式化日期查看结果 // 生成最终的Date对象 return Date(timeIntervalSince1970: timestampSec) }
额外优化点
如果你的接口里还可能出现不带偏移量的格式(比如/Date(965620800000)/),可以把正则表达式改成支持可选偏移量的版本:
let datePattern = #"\/Date\((\d+)([+-]\d{4})?\)\/"#
然后在处理偏移量的时候加个判断,如果没有偏移量就默认用GMT时区:
var offsetSeconds = 0 // 默认GMT if let offsetRange = Range(match.range(at: 2), in: dateString) { let offsetString = String(dateString[offsetRange]) let hours = Int(offsetString.prefix(3))! let minutes = Int(offsetString.suffix(2))! offsetSeconds = hours * 3600 + minutes * 60 }
验证一下
用你给出的示例日期/Date(965620800000-0400)/来测试,解码后得到的Date对象,在GMT-0400时区下格式化显示就是Mon Aug 07 2000 00:00:00 GMT-0400,完全符合预期!
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

