[SWIFT4] JSON Decoding fails to parse all valid date-time values
Created by: grEvenX
Description
The OpenAPI 3.0 specification specifies that string with format: date-time
should match the definition of date-time
specified in
https://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14.
The current implementation only handles date-time values that contains micro-seconds, which is per the RFC optional. The Swift 4 version of the library should support all valid date-time values.
openapi-generator version
3.1.2
OpenAPI declaration file content or url
https://gist.github.com/grEvenX/089a8c9ecf029560299523ff048cfd5b
Command line used for generation
docker run --rm -v $(pwd)/generated:/out openapitools/openapi-generator-cli:latest generate -I https://gist.githubusercontent.com/grEvenX/089a8c9ecf029560299523ff048cfd5b/raw/375e5a1759d3a92edab2060d08ecf0650ba8d177/example-openapi-datetime.yaml -g swift4 -o /out/swift4
Steps to reproduce
- Generate Swift4 client
- Use the generated client with a GET request containing model with date-time format
- Have the server/stub return a time in date-time format without microseconds (e.g.
2018-04-30T00:00:00+00:00
) - Run the code, the client will crash due to not being able to decode the time properly
Suggest a fix/enhancement
Currently there is a CodableHelper.swift
class generated that is used in decoding JSON.
This class opens up for providing your own DateFormatter used for parsing the dates and also provides a default code if the date formatter is not set.
The default one provided by openapi-generator should support date-time with and without microseconds, and I think we could by default set the dataformatter
to an instance of a class that we can provide, e.g. a new class OpenAPIDateFormatter
which can handle this case.
I've worked around this issue by specifying my own implementation of the DateFormatter with the following code:
import Foundation
class OpenAPIDateFormatter: DateFormatter {
override init() {
super.init()
self.calendar = Calendar(identifier: .iso8601)
self.locale = Locale(identifier: "en_US_POSIX")
self.timeZone = TimeZone(secondsFromGMT: 0)
self.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func date(from string: String) -> Date? {
if let validDate = super.date(from: string) {
return validDate
}
// first parse-attempt failed, try parsing date without micro-seconds
let newFormatter = self.copy() as! DateFormatter
newFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
return newFormatter.date(from: string)
}
}