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) | |
} |