【问题标题】:Decode date/time from String or TimeInterval in Swift从 Swift 中的 String 或 TimeInterval 解码日期/时间
【发布时间】:2021-03-01 17:03:03
【问题描述】:

我有一个需要解析的 JSON(来自第三方)。这个 JSON 返回几个嵌套对象

articles: {
  authors: {
    birthday: 'DD-MM-YYYY'
  }
  relevant_until: 'YYYY-MM-DD HH:MM:SS'
  publication_date: secondsSince1970,
  last_comment: iso8601
}

我关注this answer 拥有多个日期格式化程序并且它可以工作,只要从 JSON 中提取的每个日期都是一个字符串。

但是当谈到secondsSince1970(UNIX epoc 时间)时,我找不到将其解析为可编码对象的方法。到处看到Date(timeIntervalSince1970: timestamp),解码的时候不知道怎么用

当日期可以作为 TimeInterval 或字符串传递时,如何解析此对象上的日期?

try jsonDecoder.decode(Articles.self, from: jsonData)

【问题讨论】:

标签: json swift


【解决方案1】:

按照相同的逻辑,您可以尝试将 JSON 属性解码为 TimeInterval(或 Double),如果失败,则回退到您的 String 处理:

extension JSONDecoder {
    var dateDecodingStrategyFormatters: [DateFormatter]? {
        @available(*, unavailable, message: "This variable is meant to be set only")
        get { return nil }
        set {
            guard let formatters = newValue else { return }
            self.dateDecodingStrategy = .custom { decoder in
                let container = try decoder.singleValueContainer()
                do {
                    let timeInterval = try container.decode(TimeInterval.self)
                    return Date(timeIntervalSince1970: timeInterval)
                } catch DecodingError.typeMismatch {
                    let dateString = try container.decode(String.self)
                    
                    for formatter in formatters {
                        if let date = formatter.date(from: dateString) {
                            return date
                        }
                    }
                }

                throw DecodingError.dataCorruptedError(in: container, debugDescription: "Cannot decode date")
            }
        }
    }
}

【讨论】:

  • 为什么需要dateString = String(describing: timeInterval)?这没有任何意义
  • @LeoDabus 我这样做只是为了在最后发送DecodingError。你是对的。
  • 我会发布一个自定义的 dateDecodingStrategy 方法
  • 你们俩都发布了相同的答案,我只能同意一个。您先发布,但 Leo 发布了一个更解释的版本。感谢您的帮助,希望您能理解
【解决方案2】:
extension Formatter {
    static let iso8601withFractionalSeconds: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
        return formatter
    }()
    static let iso8601: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        return formatter
    }()
    static let ddMMyyyy: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "dd-MM-yyyy"
        return formatter
    }()
}

extension JSONDecoder.DateDecodingStrategy {
    static let multiple = custom {
        let container = try $0.singleValueContainer()
        do {
            return try Date(timeIntervalSince1970: container.decode(Double.self))
        } catch DecodingError.typeMismatch {
            let string = try container.decode(String.self)
            if let date = Formatter.iso8601withFractionalSeconds.date(from: string) ??
                Formatter.iso8601.date(from: string) ??
                Formatter.ddMMyyyy.date(from: string) {
                return date
            }
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date: \(string)")
        }
    }
}

游乐场测试:

struct Root: Codable {
    let articles: Articles
}
struct Articles: Codable {
    let authors: Authors
    let relevantUntil: Date
    let publicationDate: Date
    let lastComment: Date
}

struct Authors: Codable {
    let birthday: Date
}

let json = """
{"articles": {
              "authors": {"birthday": "01-01-1970"},
              "relevant_until": "2020-11-19 01:23:45",
              "publication_date": 1605705003.0019,
              "last_comment": "2020-11-19 01:23:45.678"}
}
"""

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .multiple
decoder.keyDecodingStrategy = .convertFromSnakeCase

do {
    let root = try decoder.decode(Root.self, from: .init(json.utf8))
    print(root.articles)  // Articles(authors: __lldb_expr_107.Authors(birthday: 1970-01-01 03:00:00 +0000), relevantUntil: 2020-11-19 04:23:45 +0000, publicationDate: 2020-11-18 13:10:03 +0000, lastComment: 2020-11-19 04:23:45 +0000)

} catch {
    print(error)
}

【讨论】:

    猜你喜欢
    • 2019-03-29
    • 2014-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多