Swift 正在获取自定义类型的日期()

Swift 正在获取自定义类型的日期(),swift,Swift,我有一个服务器API,它为JSON提供两种不同格式的日期——一种结构嵌套在另一种结构中 我的Swift应用程序使用Swift Codable解码JSON,因此我需要添加一些特殊处理,以允许解码两种自定义日期格式 很容易,我发现这可以在一个结构中处理不同的格式 struct FirstModel: Codable, Identifiable { var id: Int? let second: SecondModel let date: CustomDate<Firs

我有一个服务器API,它为JSON提供两种不同格式的日期——一种结构嵌套在另一种结构中

我的Swift应用程序使用Swift Codable解码JSON,因此我需要添加一些特殊处理,以允许解码两种自定义日期格式

很容易,我发现这可以在一个结构中处理不同的格式

struct FirstModel: Codable, Identifiable {
    var id: Int?
    let second: SecondModel
    let date: CustomDate<First>

    ...
}

struct SecondModel: Codable, Identifiable {
    var id: Int?
    let date: CustomDate<Second>

    ...
}
编译器给出了错误

无法将“Date”类型的值转换为“Date”参数的预期参数类型“CustomDate”。

我知道CustomDate(xxx)是一个DateFormatter,所以不是一个日期类型,但我甚至不知道从哪里开始获取该“类型”的新日期对象。请有人帮助以Swift编译器可以接受的方式传递当前日期的语法。谢谢

另外,我还怀疑我在某个时候需要一个“设置”编码器,对吗

更新

按照下面Joakim的建议,再加上编译器建议的修复,我尝试了

let date = try! CustomDate<First>(from: Date() as! Decoder)
let date=试试看!CustomDate(from:Date()作为!解码器)
…进行编译,但在运行时崩溃,并出现错误


无法将“Foundation.Date”类型的值强制转换为“Swift.Decoder”。

您可以创建一个自定义解码策略,在出现故障时可以返回到第二个日期格式。如果需要按照相同的规则对自定义结构进行编码,则还需要提供自定义编码方法:

首先创建日期格式化程序

extension Formatter {
    static let customUK: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_UK")
        formatter.dateFormat = "E, d MMM yyyy HH:mm zzz"
        return formatter
    }()
    static let yyyyMMdd: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_UK")
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter
    }()
}
然后你的自定义日期解码策略

extension JSONDecoder.DateDecodingStrategy {
    static let customUK = custom {
        let container = try $0.singleValueContainer()
        let string = try container.decode(String.self)
        guard
            let date = Formatter.customUK.date(from: string) ??
                Formatter.yyyyMMdd.date(from: string) else {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date: \(string)")
        }
        return date
    }
}
您的自定义编码策略也是如此

extension JSONEncoder.DateEncodingStrategy {
    static let customUK = custom {
        var container = $1.singleValueContainer()
        try container.encode(Formatter.customUK.string(from: $0))
    }
}
如果需要确保按照原始日期格式对子结构进行编码,则需要为其提供自己的编码方法:

struct First: Codable {
    var id: Int?
    let second: Second
    let date: Date
    init(id: Int?, date: Date = Date(), second: Second) {
        self.id = id
        self.date = date
        self.second = second
    }
}



操场测试:

let first = First(id: 1, second: .init(id: 2))
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .customUK
let data = try! encoder.encode(first)

print(String(data: data, encoding: .utf8)!) // {"id":1,"second":{"id":2,"date":"2020-06-02"},"date":"Tue, 2 Jun 2020 16:31 GMT-3"}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .customUK
let firstDecoded = try! decoder.decode(First.self, from: data)
print(firstDecoded)  // "First(id: Optional(1), second: __lldb_expr_227.Second(id: Optional(2), date: 2020-06-02 03:00:00 +0000), date: 2020-06-02 19:38:00 +0000)\n"

let first=FirstModel(id:nil,date:CustomDate(value:date())
谢谢@JoakimDanielson,但不幸的是,这也无法编译。编译器错误是“参数类型”Date不符合预期类型“解码器”和“调用中的参数标签不正确(具有“值:”,预期为“发件人:”)”对不起,我的错误。由于您已经实现了一个init,因此不再创建合成的init,因此在代码中手动创建对象时,您需要CustomDate使用一个新的init。是的,但是如果需要,您可以更改签名,但基本上是一个init,它以
日期
作为参数,并将其分配给
property@Snips查看我下面的帖子
struct First: Codable {
    var id: Int?
    let second: Second
    let date: Date
    init(id: Int?, date: Date = Date(), second: Second) {
        self.id = id
        self.date = date
        self.second = second
    }
}
struct Second: Decodable {
    var id: Int?
    let date: Date
    init(id: Int?, date: Date = Date()) {
        self.id = id
        self.date = date
    }
}
extension Second: Encodable {
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(Formatter.yyyyMMdd.string(for: date), forKey: .date)
    }
}
let first = First(id: 1, second: .init(id: 2))
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .customUK
let data = try! encoder.encode(first)

print(String(data: data, encoding: .utf8)!) // {"id":1,"second":{"id":2,"date":"2020-06-02"},"date":"Tue, 2 Jun 2020 16:31 GMT-3"}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .customUK
let firstDecoded = try! decoder.decode(First.self, from: data)
print(firstDecoded)  // "First(id: Optional(1), second: __lldb_expr_227.Second(id: Optional(2), date: 2020-06-02 03:00:00 +0000), date: 2020-06-02 19:38:00 +0000)\n"