使用 JSONDecoder 解码古怪的日期格式
Decoding oddball date format with JSONDecoder
我在 JSON return.
中得到了以前从未见过的日期格式
"/Date(965620800000-0400)/"
(是Mon Aug 07 2000 00:00:00 GMT-0400
)
这是一个以毫秒为单位的日期值,具有 GMT 偏移量。我正在尝试使用 Swift 的原生 JSONDecoder
并设置 dateDecodingStrategy
.
最初,我试过这个:
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
正如我最初所怀疑的那样,由于额外的非数字字符,它不起作用。这是我得到的初始错误:
debugDescription: "Expected to decode Double but found a string/data
instead.", underlyingError: nil)) The data couldn’t be read because it
isn’t in the correct format.
我在 Unicode.org and found this 上搜索了一下,它说 A
代表毫秒,Z
是 ISO8601 基本格式,有小时、分钟和可选的秒字段。
考虑到这一点,我做了一个 DateFormatter
扩展:
extension DateFormatter {
static let nhtsaFormat: DateFormatter = {
let formatter = DateFormatter()
// This is the string that comes back --> "/Date(965620800000-0400)/"
// These are the formats I tried:
formatter.dateFormat = "'/Date('AZ')/'"
// formatter.dateFormat = "'/Date('A')/'"
// formatter.dateFormat = "'/Date('A`-`Z')/'"
// formatter.dateFormat = "'/Date('A'-'Z')/'"
// formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
}
在我的 DataManager
class 上,我将 decoder.dateDecodingStrategy
更改为我的自定义格式,如下所示:
decoder.dateDecodingStrategy = .formatted(.nhtsaFormat)
对于各种格式中的每一种,我仍然会收到此错误:
debugDescription: "Expected to decode Double but found a string/data
instead.", underlyingError: nil)) The data couldn’t be read because it
isn’t in the correct format.
我尝试从我的 Codable
结构中删除有问题的日期键,我得到了正确的 returns,但不幸的是,我也需要日期。非常感谢任何关于如何解码该字符串的建议。
您无法使用标准 DateFormatter
解析此类日期字符串,因为没有表示 "seconds (or milliseconds) since epoch" 的标准格式说明符。 A
格式说明符用于 "seconds in day".
一种解决方案是使用 .custom
日期解码策略和可以解析此类字符串的自定义方法。
这是一些有效的测试代码:
func customDateParser(_ decoder: Decoder) throws -> Date {
let dateString = try decoder.singleValueContainer().decode(String.self)
let scanner = Scanner(string: dateString)
var millis: Int64 = 0
if scanner.scanString("/Date(", into: nil) &&
scanner.scanInt64(&millis) &&
scanner.scanInt(nil) &&
scanner.scanString(")/", into: nil) &&
scanner.isAtEnd {
return Date(timeIntervalSince1970: TimeInterval(millis) / 1000)
} else {
return Date() // TODO - unexpected format, throw error
}
}
let json = "{ \"date\": \"/Date(965620800000-0400)/\" }".data(using: .utf8)!
struct Test: Decodable {
var date: Date
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom(customDateParser)
let test = try! decoder.decode(Test.self, from: json)
print(test)
请注意,日期字符串中的时区偏移量是无关紧要的。不需要生成正确的 Date
实例。
我将错误处理留作 reader 的练习。
我在 JSON return.
中得到了以前从未见过的日期格式"/Date(965620800000-0400)/"
(是Mon Aug 07 2000 00:00:00 GMT-0400
)
这是一个以毫秒为单位的日期值,具有 GMT 偏移量。我正在尝试使用 Swift 的原生 JSONDecoder
并设置 dateDecodingStrategy
.
最初,我试过这个:
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
正如我最初所怀疑的那样,由于额外的非数字字符,它不起作用。这是我得到的初始错误:
debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil)) The data couldn’t be read because it isn’t in the correct format.
我在 Unicode.org and found this 上搜索了一下,它说 A
代表毫秒,Z
是 ISO8601 基本格式,有小时、分钟和可选的秒字段。
考虑到这一点,我做了一个 DateFormatter
扩展:
extension DateFormatter {
static let nhtsaFormat: DateFormatter = {
let formatter = DateFormatter()
// This is the string that comes back --> "/Date(965620800000-0400)/"
// These are the formats I tried:
formatter.dateFormat = "'/Date('AZ')/'"
// formatter.dateFormat = "'/Date('A')/'"
// formatter.dateFormat = "'/Date('A`-`Z')/'"
// formatter.dateFormat = "'/Date('A'-'Z')/'"
// formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
}
在我的 DataManager
class 上,我将 decoder.dateDecodingStrategy
更改为我的自定义格式,如下所示:
decoder.dateDecodingStrategy = .formatted(.nhtsaFormat)
对于各种格式中的每一种,我仍然会收到此错误:
debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil)) The data couldn’t be read because it isn’t in the correct format.
我尝试从我的 Codable
结构中删除有问题的日期键,我得到了正确的 returns,但不幸的是,我也需要日期。非常感谢任何关于如何解码该字符串的建议。
您无法使用标准 DateFormatter
解析此类日期字符串,因为没有表示 "seconds (or milliseconds) since epoch" 的标准格式说明符。 A
格式说明符用于 "seconds in day".
一种解决方案是使用 .custom
日期解码策略和可以解析此类字符串的自定义方法。
这是一些有效的测试代码:
func customDateParser(_ decoder: Decoder) throws -> Date {
let dateString = try decoder.singleValueContainer().decode(String.self)
let scanner = Scanner(string: dateString)
var millis: Int64 = 0
if scanner.scanString("/Date(", into: nil) &&
scanner.scanInt64(&millis) &&
scanner.scanInt(nil) &&
scanner.scanString(")/", into: nil) &&
scanner.isAtEnd {
return Date(timeIntervalSince1970: TimeInterval(millis) / 1000)
} else {
return Date() // TODO - unexpected format, throw error
}
}
let json = "{ \"date\": \"/Date(965620800000-0400)/\" }".data(using: .utf8)!
struct Test: Decodable {
var date: Date
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom(customDateParser)
let test = try! decoder.decode(Test.self, from: json)
print(test)
请注意,日期字符串中的时区偏移量是无关紧要的。不需要生成正确的 Date
实例。
我将错误处理留作 reader 的练习。