可以扩展 MKGeoJSONDecoder 以像 JSONDecoder 一样解析 ISO8601 日期吗?
Can MKGeoJSONDecoder be extended to parse ISO8601 dates like JSONDecoder?
我有来自 API 的 GeoJSON 数据,它包含 ISO8601 格式的日期。我可以在 SwiftUI 中将它们解码为字符串,并通过计算字段对它们进行操作以获得 Date 类型的版本,但它很笨拙。
我知道 JSONDecoder 支持日期 en/decoding 选项,我想要相同的行为..类似于:
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
我正在考虑 MKGeoJSONDecoder 的扩展,但由于需要进入解析流程,我什至不知道如何开始。
想法?谢谢
谢谢 vadian,我想要的所有数据都在 properties 属性中,所以使用 MKGeoJSONDecoder 真的没有任何价值。我刚刚切换到普通的 JSONDecoder 并放置了一个自定义的 ISO8601 格式化程序来匹配我的数据并且一切正常。
如果有人想参考,这里是 playground 代码。你当然想添加一堆错误检查。感谢 Sarunw 提供有关自定义日期解码的重要信息 (https://sarunw.com/posts/how-to-parse-iso8601-date-in-swift/)
import Foundation
import MapKit
struct Response: Codable {
let features: [Feature]
}
struct Feature: Codable {
let properties: Properties
}
struct Properties: Codable {
let stnNamValue: String?
let dateTmValue: Date?
enum CodingKeys: String, CodingKey {
case stnNamValue = "stn_nam-value"
case dateTmValue = "date_tm-value"
}
}
Task {
// get the data from API
let url = URL(string: "https://api.weather.gc.ca/collections/swob-realtime/items?f=json&sortby=-date_tm-value&clim_id-value=5050919&limit=3")
let (data, _) = try await URLSession.shared.data(from: url!)
// create the decoder with custom ISO8601 formatter
let decoder = JSONDecoder()
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withFullDate, .withFullTime,.withFractionalSeconds, .withTimeZone]
decoder.dateDecodingStrategy = .custom({ decoder in
let container = try decoder.singleValueContainer()
let dateString = try container.decode(String.self)
if let date = formatter.date(from: dateString) {return date}
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Cannot decode date string \(dateString)")
})
// decode & print the results
let decodedResponse = try decoder.decode(Response.self, from: data)
decodedResponse.features.forEach {(feature) in
print("Station: \(feature.properties.stnNamValue ?? "<no value>"), Date: \(feature.properties.dateTmValue)")
}
}
输出是 date/times 马尼托巴省 Flin Flon 的最新地面天气观测结果:
Station: FLIN FLON, Date: Optional(2022-02-16 12:22:00 +0000)
Station: FLIN FLON, Date: Optional(2022-02-16 12:21:00 +0000)
Station: FLIN FLON, Date: Optional(2022-02-16 12:20:00 +0000)
我有来自 API 的 GeoJSON 数据,它包含 ISO8601 格式的日期。我可以在 SwiftUI 中将它们解码为字符串,并通过计算字段对它们进行操作以获得 Date 类型的版本,但它很笨拙。 我知道 JSONDecoder 支持日期 en/decoding 选项,我想要相同的行为..类似于:
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
我正在考虑 MKGeoJSONDecoder 的扩展,但由于需要进入解析流程,我什至不知道如何开始。
想法?谢谢
谢谢 vadian,我想要的所有数据都在 properties 属性中,所以使用 MKGeoJSONDecoder 真的没有任何价值。我刚刚切换到普通的 JSONDecoder 并放置了一个自定义的 ISO8601 格式化程序来匹配我的数据并且一切正常。
如果有人想参考,这里是 playground 代码。你当然想添加一堆错误检查。感谢 Sarunw 提供有关自定义日期解码的重要信息 (https://sarunw.com/posts/how-to-parse-iso8601-date-in-swift/)
import Foundation
import MapKit
struct Response: Codable {
let features: [Feature]
}
struct Feature: Codable {
let properties: Properties
}
struct Properties: Codable {
let stnNamValue: String?
let dateTmValue: Date?
enum CodingKeys: String, CodingKey {
case stnNamValue = "stn_nam-value"
case dateTmValue = "date_tm-value"
}
}
Task {
// get the data from API
let url = URL(string: "https://api.weather.gc.ca/collections/swob-realtime/items?f=json&sortby=-date_tm-value&clim_id-value=5050919&limit=3")
let (data, _) = try await URLSession.shared.data(from: url!)
// create the decoder with custom ISO8601 formatter
let decoder = JSONDecoder()
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withFullDate, .withFullTime,.withFractionalSeconds, .withTimeZone]
decoder.dateDecodingStrategy = .custom({ decoder in
let container = try decoder.singleValueContainer()
let dateString = try container.decode(String.self)
if let date = formatter.date(from: dateString) {return date}
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Cannot decode date string \(dateString)")
})
// decode & print the results
let decodedResponse = try decoder.decode(Response.self, from: data)
decodedResponse.features.forEach {(feature) in
print("Station: \(feature.properties.stnNamValue ?? "<no value>"), Date: \(feature.properties.dateTmValue)")
}
}
输出是 date/times 马尼托巴省 Flin Flon 的最新地面天气观测结果:
Station: FLIN FLON, Date: Optional(2022-02-16 12:22:00 +0000)
Station: FLIN FLON, Date: Optional(2022-02-16 12:21:00 +0000)
Station: FLIN FLON, Date: Optional(2022-02-16 12:20:00 +0000)