Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Json 带空字符串或零的Swift可解码日期 情况_Json_Swift_String_Codable_Decodable - Fatal编程技术网

Json 带空字符串或零的Swift可解码日期 情况

Json 带空字符串或零的Swift可解码日期 情况,json,swift,string,codable,decodable,Json,Swift,String,Codable,Decodable,我正在处理一个具有多个日期字段的API服务器,我已经看到这些日期字段的API响应可以是: { "clicktimestamp": "", "clicktimestamp": " ", "clicktimestamp": "2020-08-08 16:13:17" } JSON响应可以是: •字符串没有空白 •带空格的字符串 •带有某些日期格式的字符串 我没有访问A

我正在处理一个具有多个日期字段的API服务器,我已经看到这些日期字段的API响应可以是:

{
 "clicktimestamp": "",
 "clicktimestamp": "  ",  
 "clicktimestamp": "2020-08-08 16:13:17"
}
JSON响应可以是: •字符串没有空白 •带空格的字符串 •带有某些日期格式的字符串

我没有访问API服务器的权限,也不能要求服务器端工程师对其进行更改。我的情况并不理想,所以我必须处理它

工作解决方案不是很快 我写了一些代码来处理这种情况。它是有效的,但它的某些方面感觉不是很快

考虑到我的JSON响应情况,如何改进整个解码过程? 还是很好

以下是一个可行的解决方案:

import UIKit
import Foundation

struct ProductDate: Decodable, Hashable {
    var lastcheckedtime: Date?
    var oktime: Date?
    var clicktimestamp: Date?
    var lastlocaltime: Date?
    // I have more properties but I'm omitting them
}

extension ProductDate {
    
    private enum Keys: String, CodingKey {
        case lastcheckedtime
        case oktime
        case clicktimestamp
        case lastlocaltime
    }
    
    init(from decoder: Decoder) throws {
        
        let formatter = DateFormatter.yyyyMMdd
        let container = try decoder.container(keyedBy: Keys.self)
    
        let dateKeys: [KeyedDecodingContainer<Keys>.Key] = [
            .lastcheckedtime,
            .oktime,
            .clicktimestamp,
            .lastlocaltime
        ]

        let parseDate: (String, KeyedDecodingContainer<Keys>.Key, KeyedDecodingContainer<Keys>) throws -> Date? = {(dateString, someKey, container) in
             if !dateString.isEmpty {
                 if let date = formatter.date(from: dateString) {
                     return date
                 } else {
                     throw DecodingError.dataCorruptedError(forKey: someKey,
                                     in: container,
                                     debugDescription: "Date string does not match format expected by formatter.")
                 }
             } else {
                 return nil
             }
         }

        let datesResults: [Date?] = try dateKeys.map({ key in
            // 1.  decode as a string because we sometimes get "" or  " " for those date fields as the API server is poorly managed.
            let dateString = try container.decode(String.self, forKey: key)
                                            .trimmingCharacters(in: .whitespaces)
            // 2. now pass in our dateString which could be "" or " " or "2020-08-08 16:13:17"
            // and try to parse it into a Date or nil
            let result = try parseDate(dateString, key, container)
            return result
        })

        // 3. Assign our array of dateResults to our struct keys
        lastcheckedtime = datesResults[0]
        oktime          = datesResults[1]
        clicktimestamp  = datesResults[2]
        lastlocaltime   = datesResults[3]
        
        
    }
    
}


extension DateFormatter {
  static let yyyyMMdd: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "YYYY-MM-DD HH:mm:ss"
    formatter.calendar = Calendar(identifier: .iso8601)
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    formatter.locale = Locale(identifier: "en_US_POSIX")
    return formatter
  }()
}


let json = """
{
   "lastcheckedtime": "",
   "oktime": " ",
   "clicktimestamp": "",
   "lastlocaltime": "2020-08-08 16:13:17"
}
""".data(using: .utf8)!


let decoder = JSONDecoder()


print(json)

do {
    let decoded = try decoder.decode(ProductDate.self, from: json)
    print(decoded)
} catch let context {
   print(context)
}


太复杂了

添加DateDecoding策略并解码日期。如果失败,则分配nil

不需要修剪材料

还要注意,您的日期格式是错误的

struct ProductDate: Decodable, Hashable {
    var lastcheckedtime: Date?
    var oktime: Date?
    var clicktimestamp: Date?
    var lastlocaltime: Date?
}

extension ProductDate {
    
    private enum CodingKeys: String, CodingKey {
        case lastcheckedtime, oktime, clicktimestamp, lastlocaltime
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        lastcheckedtime = try? container.decode(Date.self, forKey: .lastcheckedtime)
        oktime = try? container.decode(Date.self, forKey: .oktime)
        clicktimestamp = try? container.decode(Date.self, forKey: .clicktimestamp)
        lastlocaltime = try? container.decode(Date.self, forKey: .lastlocaltime)
    }
}


extension DateFormatter {
  static let yyyyMMdd: DateFormatter = {
    let formatter = DateFormatter()
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    return formatter
  }()
}


let json = """
{
   "lastcheckedtime": "",
   "oktime": " ",
   "clicktimestamp": "",
   "lastlocaltime": "2020-08-08 16:13:17"
}
"""


let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(.yyyyMMdd)


print(json)

do {
    let decoded = try decoder.decode(ProductDate.self, from: Data(json.utf8))
    print(decoded)
} catch let context {
   print(context)
}
太复杂了

添加DateDecoding策略并解码日期。如果失败,则分配nil

不需要修剪材料

还要注意,您的日期格式是错误的

struct ProductDate: Decodable, Hashable {
    var lastcheckedtime: Date?
    var oktime: Date?
    var clicktimestamp: Date?
    var lastlocaltime: Date?
}

extension ProductDate {
    
    private enum CodingKeys: String, CodingKey {
        case lastcheckedtime, oktime, clicktimestamp, lastlocaltime
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        lastcheckedtime = try? container.decode(Date.self, forKey: .lastcheckedtime)
        oktime = try? container.decode(Date.self, forKey: .oktime)
        clicktimestamp = try? container.decode(Date.self, forKey: .clicktimestamp)
        lastlocaltime = try? container.decode(Date.self, forKey: .lastlocaltime)
    }
}


extension DateFormatter {
  static let yyyyMMdd: DateFormatter = {
    let formatter = DateFormatter()
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    return formatter
  }()
}


let json = """
{
   "lastcheckedtime": "",
   "oktime": " ",
   "clicktimestamp": "",
   "lastlocaltime": "2020-08-08 16:13:17"
}
"""


let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(.yyyyMMdd)


print(json)

do {
    let decoded = try decoder.decode(ProductDate.self, from: Data(json.utf8))
    print(decoded)
} catch let context {
   print(context)
}

我将使用如下DateDecoding策略为解码器设置自定义日期格式化程序

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(DateFormatter.yyyyMMdd)
然后在自定义初始化中,我首先解码为字符串,检查它是否为空,如果不是,然后解码为使用上述格式化程序的日期

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: Keys.self)
    if try !container.decode(String.self, forKey: .lastcheckedtime).trimmingCharacters(in: .whitespaces).isEmpty {
        lastcheckedtime = try container.decode(Date.self, forKey: .lastcheckedtime)
    }
    if try !container.decode(String.self, forKey: .oktime).trimmingCharacters(in: .whitespaces).isEmpty {
        oktime = try container.decode(Date.self, forKey: .oktime)
    }
    if try !container.decode(String.self, forKey: .clicktimestamp).trimmingCharacters(in: .whitespaces).isEmpty {
        clicktimestamp = try container.decode(Date.self, forKey: .clicktimestamp)
    }
    if try !container.decode(String.self, forKey: .lastlocaltime).trimmingCharacters(in: .whitespaces).isEmpty {
        lastlocaltime = try container.decode(Date.self, forKey: .lastlocaltime)
    }
}

我将使用如下DateDecoding策略为解码器设置自定义日期格式化程序

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(DateFormatter.yyyyMMdd)
然后在自定义初始化中,我首先解码为字符串,检查它是否为空,如果不是,然后解码为使用上述格式化程序的日期

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: Keys.self)
    if try !container.decode(String.self, forKey: .lastcheckedtime).trimmingCharacters(in: .whitespaces).isEmpty {
        lastcheckedtime = try container.decode(Date.self, forKey: .lastcheckedtime)
    }
    if try !container.decode(String.self, forKey: .oktime).trimmingCharacters(in: .whitespaces).isEmpty {
        oktime = try container.decode(Date.self, forKey: .oktime)
    }
    if try !container.decode(String.self, forKey: .clicktimestamp).trimmingCharacters(in: .whitespaces).isEmpty {
        clicktimestamp = try container.decode(Date.self, forKey: .clicktimestamp)
    }
    if try !container.decode(String.self, forKey: .lastlocaltime).trimmingCharacters(in: .whitespaces).isEmpty {
        lastlocaltime = try container.decode(Date.self, forKey: .lastlocaltime)
    }
}

在设置日期格式之前,应始终设置区域设置。您确定日期字符串是UTC吗?通常,没有时区信息的日期字符串应视为本地时间。在设置日期格式之前,应始终设置区域设置。您确定日期字符串是UTC吗?通常,没有时区信息的日期字符串应视为本地时间。