Skip to content

Instantly share code, notes, and snippets.

@bergusman
Last active September 6, 2021 14:23
Show Gist options
  • Save bergusman/8d2f835702db28df4f1e051f777a1b6a to your computer and use it in GitHub Desktop.
Save bergusman/8d2f835702db28df4f1e051f777a1b6a to your computer and use it in GitHub Desktop.
The Internet Date/Time Format (RFC 3339) with JSON
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)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment