json - Swift JSON Search Date format by Year-month?
问题描述
我正在使用 Eodhistoricaldata.com 的 API 来获取问题的月度值。
https://eodhistoricaldata.com/api/eod/VTSMX?from=2017-09-01&api_token=xxxxxx&period=m&fmt=json
即使是月度数据,他们也会将第一个交易日期分配给结果。-01、-02、-03 等
这意味着我不能使用通用日期 -01。所以 YYYY-MM-01 不起作用。
因此,我要么必须将所有日期更改为 -01,要么仅按年份和月份进行搜索,例如“2017-10”
使用 Swift 4 和 SwiftyJSON 完成此任务的最佳方法是什么?
谢谢。
这是他们的数据。
[{"date":"2017-09-01","open":"61.9300","high":63.03,"low":"61.4400","close":63.03,"adjusted_close":61.6402,"volume":0},
{"date":"2017-10-02","open":"63.3400","high":"64.5300","low":"63.3400","close":64.39,"adjusted_close":62.9703,"volume":0},
{"date":"2017-11-01","open":"64.4400","high":66.35,"low":"64.0600","close":66.35,"adjusted_close":64.8872,"volume":0},
{"date":"2017-12-01","open":"66.2100","high":"67.3500","low":"65.7700","close":66.7,"adjusted_close":65.5322,"volume":0},
{"date":"2018-01-02","open":"67.2500","high":"71.4800","low":"67.2500","close":70.24,"adjusted_close":69.0102,"volume":0},
{"date":"2018-02-01","open":"70.2400","high":"70.2400","low":"64.4000","close":67.63,"adjusted_close":66.4458,"volume":0},
....
{"date":"2018-12-03","open":"69.5700","high":"69.5700","low":"58.1700","close":62.08,"adjusted_close":62.08,"volume":0}]
解决方案
删除 SwiftyJSON 并用于Decodable
将 JSON 解析为结构。解析日期是高度可定制的。您可以添加自己的逻辑,从日期字符串中提取年份和月份并创建一个Date
实例。
struct HistoricalData: Decodable {
let date: Date
let open, low, high : String
let close, adjustedClose, volume : Double
}
...
let jsonString = """
[{"date":"2017-09-01","open":"61.9300","high":"63.03","low":"61.4400","close":63.03,"adjusted_close":61.6402,"volume":0},
{"date":"2017-10-02","open":"63.3400","high":"64.5300","low":"63.3400","close":64.39,"adjusted_close":62.9703,"volume":0},
{"date":"2017-11-01","open":"64.4400","high":"66.35","low":"64.0600","close":66.35,"adjusted_close":64.8872,"volume":0},
{"date":"2017-12-01","open":"66.2100","high":"67.3500","low":"65.7700","close":66.7,"adjusted_close":65.5322,"volume":0},
{"date":"2018-01-02","open":"67.2500","high":"71.4800","low":"67.2500","close":70.24,"adjusted_close":69.0102,"volume":0},
{"date":"2018-02-01","open":"70.2400","high":"70.2400","low":"64.4000","close":67.63,"adjusted_close":66.4458,"volume":0},
{"date":"2018-12-03","open":"69.5700","high":"69.5700","low":"58.1700","close":62.08,"adjusted_close":62.08,"volume":0}]
"""
let data = Data(jsonString.utf8)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .custom { decoder -> Date in
let container = try decoder.singleValueContainer()
let dateStr = try container.decode(String.self)
let components = dateStr.components(separatedBy: "-")
guard components.count > 2, let year = Int(components[0]), let month = Int(components[1]) else { throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date string") }
return Calendar.current.date(from: DateComponents(year: year, month: month))!
}
do {
let result = try decoder.decode([HistoricalData].self, from: data)
print(result)
} catch { print(error) }
或者,您可以将字符串解码为格式,yyyy-MM
但是您必须编写初始化程序并添加 CodingKeys
struct HistoricalData: Decodable {
let date: String
let open, low, high : String
let close, adjustedClose, volume : Double
private enum CodingKeys : String, CodingKey {
case date, open, low, high, close, adjustedClose, volume
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let dateString = try container.decode(String.self, forKey: .date)
guard let secondDashRange = dateString.range(of: "-", options: .backwards) else {
throw DecodingError.dataCorruptedError(forKey: .date, in: container, debugDescription: "Invalid date string")
}
date = String(dateString[..<secondDashRange.lowerBound])
open = try container.decode(String.self, forKey: .open)
low = try container.decode(String.self, forKey: .low)
high = try container.decode(String.self, forKey: .high)
close = try container.decode(Double.self, forKey: .close)
adjustedClose = try container.decode(Double.self, forKey: .adjustedClose)
volume = try container.decode(Double.self, forKey: .volume)
}
}
let data = Data(jsonString.utf8)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
let result = try decoder.decode([HistoricalData].self, from: data)
print(result)
} catch { print(error) }
推荐阅读
- uicollectionview - 如何为 UICollectionViewCompositionalLayout 的每个部分制作标题
- algorithm - 取最高项的算法的时间复杂度
- graphql - Gatsby - 使用组在 createResolver 中运行查询
- javascript - 警告:validateDOMNesting(…):
- r - 使用 dplyr 仅对某些列执行操作
- flutter-layout - 当我将 debugPaintSizeEnabled 设置为 true 时,flutter 应用程序上的点是什么?
- dax - Dax 首次通过率
- r - 与 R 中超过 2 个变量的自举相关性
- c# - (已解决)IO异常 进程无法访问该文件,因为它正在被另一个进程使用
- google-tag-manager - GTM 跟踪 JQuery 点击事件