Examples how encode/decode RFC 3339 (ISO 8601) dates in JSON by JSONEncoder/JSONDecoder.
Links:
Sources:
Examples how encode/decode RFC 3339 (ISO 8601) dates in JSON by JSONEncoder/JSONDecoder.
Links:
Sources:
| do { | |
| let options: ISO8601DateFormatter.Options = .withInternetDateTime | |
| let cfOptions = CFISO8601DateFormatOptions(rawValue: options.rawValue) | |
| let cfFormatter = CFDateFormatterCreateISO8601Formatter(kCFAllocatorSystemDefault, cfOptions) | |
| let format = CFDateFormatterGetFormat(cfFormatter) as String | |
| print(format) // yyyy-MM-dd'T'HH:mm:ssXXXXX | |
| } | |
| do { | |
| let options: ISO8601DateFormatter.Options = [.withInternetDateTime, .withFractionalSeconds] | |
| let cfOptions = CFISO8601DateFormatOptions(rawValue: options.rawValue) | |
| let cfFormatter = CFDateFormatterCreateISO8601Formatter(kCFAllocatorSystemDefault, cfOptions) | |
| let format = CFDateFormatterGetFormat(cfFormatter) as String | |
| print(format) // yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX | |
| } |
| // Decoding with/without fractional seconds | |
| let formatter1 = ISO8601DateFormatter() | |
| formatter1.formatOptions = .withInternetDateTime | |
| let formatter2 = ISO8601DateFormatter() | |
| formatter2.formatOptions = [.withInternetDateTime, .withFractionalSeconds] | |
| let decoder = JSONDecoder() | |
| decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in | |
| let container = try decoder.singleValueContainer() | |
| let string = try container.decode(String.self) | |
| if let date = formatter1.date(from: string) { | |
| return date | |
| } else if let date = formatter2.date(from: string) { | |
| return date | |
| } | |
| throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date string: \(string)") | |
| }) | |
| struct Mix: Decodable { | |
| let date1: Date | |
| let date2: Date | |
| } | |
| let json = #"{"date1": "2021-06-19T10:30:00Z", "date2": "2021-06-19T10:30:00.123Z"}"# | |
| do { | |
| let mix = try decoder.decode(Mix.self, from: json.data(using: .utf8)!) | |
| print(mix) | |
| } catch { | |
| print(error) | |
| } |
| // Encoding & decoding with fractional seconds by .custom strategy | |
| let formatter = ISO8601DateFormatter() | |
| formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] | |
| let encoder = JSONEncoder() | |
| encoder.dateEncodingStrategy = .custom({ (date, encoder) in | |
| var container = encoder.singleValueContainer() | |
| try container.encode(formatter.string(from: date)) | |
| }) | |
| let decoder = JSONDecoder() | |
| decoder.dateDecodingStrategy = .custom({ (decoder) in | |
| let container = try decoder.singleValueContainer() | |
| let string = try container.decode(String.self) | |
| if let date = formatter.date(from: string) { | |
| return date | |
| } | |
| throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date string: \(string)") | |
| }) | |
| do { | |
| let now = Date() | |
| print("date: ", now) | |
| let data = try encoder.encode(now) | |
| print("encoded:", String(data: data, encoding: .utf8)!) | |
| let date = try decoder.decode(Date.self, from: data) | |
| print("decoded:", date) | |
| } catch { | |
| print(error) | |
| } |
| // Encoding & decoding with fractional seconds by .formatted strategy | |
| // Date format patterns: https://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns | |
| let formatter = DateFormatter() | |
| formatter.locale = .init(identifier: "en_US_POSIX") | |
| formatter.timeZone = TimeZone(identifier: "GMT") | |
| formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX" | |
| let encoder = JSONEncoder() | |
| encoder.dateEncodingStrategy = .formatted(formatter) | |
| let decoder = JSONDecoder() | |
| decoder.dateDecodingStrategy = .formatted(formatter) | |
| do { | |
| let now = Date() | |
| print("date: ", now) | |
| let data = try encoder.encode(now) | |
| print("encoded:", String(data: data, encoding: .utf8)!) | |
| let date = try decoder.decode(Date.self, from: data) | |
| print("decoded:", date) | |
| } catch { | |
| print(error) | |
| } |
| // Encoding & decoding without fractional seconds | |
| let encoder = JSONEncoder() | |
| encoder.dateEncodingStrategy = .iso8601 | |
| let decoder = JSONDecoder() | |
| decoder.dateDecodingStrategy = .iso8601 | |
| do { | |
| let now = Date() | |
| print("date: ", now) | |
| let data = try encoder.encode(now) | |
| print("encoded:", String(data: data, encoding: .utf8)!) | |
| let date = try decoder.decode(Date.self, from: data) | |
| print("decoded:", date) | |
| } catch { | |
| print(error) | |
| } |