8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

如何在 Swift 中使用 Codable 转换带有可选秒小数部分的日期字符串?

JW. 1月前

125 0

我正在用 Swift 的 Codable 替换旧的 JSON 解析代码,遇到了一点麻烦。我想这与其说是 Codable 问题,不如说是 DateFormatter 问题。从结构开始

我正在用 Swift 的 Codable 替换旧的 JSON 解析代码,但遇到了一些问题。我想这与其说是 Codable 的问题,不如说是 DateFormatter 的问题。

从结构体开始

 struct JustADate: Codable {
    var date: Date
 }

和一个 json 字符串

let json = """
  { "date": "2017-06-19T18:43:19Z" }
"""

现在让我们解码

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601

let data = json.data(using: .utf8)!
let justADate = try! decoder.decode(JustADate.self, from: data) //all good

但是如果我们将日期更改为具有秒的小数部分,例如:

let json = """
  { "date": "2017-06-19T18:43:19.532Z" }
"""

现在它坏了。日期有时会返回小数秒,有时则不会。我以前解决这个问题的方法是在我的映射代码中,我有一个转换函数,它尝试了带小数秒和不带小数秒的 dateFormats。不过,我不太确定如何使用 Codable 来解决这个问题。有什么建议吗?

帖子版权声明 1、本帖标题:如何在 Swift 中使用 Codable 转换带有可选秒小数部分的日期字符串?
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由JW.在本站《date》版块原创发布, 转载请注明出处!
最新回复 (0)
  • Swift 5

    要将 ISO8601 字符串解析为日期,您必须使用 DateFormatter。在较新的系统(例如 iOS11+)中,您可以使用 ISO8601DateFormatter。

    只要您不知道日期是否包含毫秒,就应该为每种情况创建 2 个格式化程序。然后,在将字符串解析为日期时依次使用两者。

    适用于旧系统的 DateFormatter

    /// Formatter for ISO8601 with milliseconds
    lazy var iso8601FormatterWithMilliseconds: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: "en_US_POSIX")
        dateFormatter.timeZone = TimeZone(abbreviation: "GMT")
        dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
    
        return dateFormatter
    }()
    
    /// Formatter for ISO8601 without milliseconds
    lazy var iso8601Formatter: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: "en_US_POSIX")
        dateFormatter.timeZone = TimeZone(abbreviation: "GMT")
        dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
    
        return dateFormatter
    }()
    

    适用于较新系统的 ISO8601DateFormatter(例如 iOS 11+)

    lazy var iso8601FormatterWithMilliseconds: ISO8601DateFormatter = {
        let formatter = ISO8601DateFormatter()
    
        // GMT or UTC -> UTC is standard, GMT is TimeZone
        formatter.timeZone = TimeZone(abbreviation: "GMT")
        formatter.formatOptions = [.withInternetDateTime,
                                   .withDashSeparatorInDate,
                                   .withColonSeparatorInTime,
                                   .withTimeZone,
                                   .withFractionalSeconds]
    
        return formatter
    }()
    
    /// Formatter for ISO8601 without milliseconds
    lazy var iso8601Formatter: ISO8601DateFormatter = {
        let formatter = ISO8601DateFormatter()
    
        // GMT or UTC -> UTC is standard, GMT is TimeZone
        formatter.timeZone = TimeZone(abbreviation: "GMT")
        formatter.formatOptions = [.withInternetDateTime,
                                   .withDashSeparatorInDate,
                                   .withColonSeparatorInTime,
                                   .withTimeZone]
    
        return formatter
    }()
    

    概括

    如您所见,需要创建 2 个格式化程序。如果您想支持较旧的系统,则需要创建 4 个格式化程序。为了更简单,请查看 GitHub 上的 Tomorrow ,您可以在那里看到此问题的完整解决方案。

    要将字符串转换为日期,请使用:

    let date = Date.fromISO("2020-11-01T21:10:56.22+02:00")

返回
作者最近主题: