I need to parse the following date in a JSON payload and it's almost in ISO8601 format.
"2020-06-05 14:52:54 UTC"
To conform to ISO8601 it needs to be altered slightly.
"2020-06-05T14:52:54Z"
It's super annoying because I now have to make a customer date decoding strategy.
static func make() -> JSONDecoder {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
// decoder.dateDecodingStrategy = .iso8601
decoder.dateDecodingStrategy = .custom({ decoder in
let container = try decoder.singleValueContainer()
let dateStr = try container.decode(String.self)
guard let date = formatter.date(from: dateStr) else {
preconditionFailure("Unexpected date format.")
}
return date
})
return decoder
}
I don't have control of the data source. Is there anything I can do to avoid a custom decoding strategy in this case?
CodePudding user response:
Since you seem to just want to use a DateFormatter
to parse the date string, use the formatted
strategy.
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss zzzz"
// or
// formatter.dateFormat = "yyyy-MM-dd HH:mm:ss 'UTC'"
// formatter.timeZone = .init(identifier: "UTC")
formatter.locale = Locale(identifier: "en_US_POSIX")
decoder.dateDecodingStrategy = .formatted(formatter)
CodePudding user response:
An alternative to Sweeper's answer is to write an extension of DateFormatter
extension DateFormatter {
static let almostISO8601Formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
return formatter
}()
}
Then your make()
function simply becomes
static func make() -> JSONDecoder {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(.almostISO8601Formatter)
return decoder
}
Consider also to put make()
(with a more meaningful name) in an extension of JSONDecoder
CodePudding user response:
You could map your input into iso8601, to use an existing decoder:
func iso8601ify(_ str: String) -> String {
str.split(separator: " ")
.prefix(2)
.joined(separator: "T")
.appending("Z")
}
This example, there's no error handling, of course