You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Swift的JSONDecoder解析/Date(xxx-xxxx)/格式日期

解决Swift中解析"/Date(时间戳-偏移量)/"格式日期的问题

我之前也碰到过这种.NET风格的日期格式,确实挺让人头疼的!原生的JSONDecoder日期解码策略直接用.millisecondsSince1970肯定不行,因为这个格式里混了字符串和偏移量信息,咱们得自定义一个解码逻辑来搞定它。

核心思路

这种格式的结构是/Date(毫秒时间戳±GMT偏移量)/,咱们需要:

  1. 从字符串中提取出毫秒时间戳和时区偏移量
  2. 将偏移量转换为对应的TimeZone
  3. 用时间戳生成正确的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:07:49