ISO8601DateFormatter doesn't parse ISO date string
Prior to macOS 10.13 / iOS 11 ISO8601DateFormatter
does not support date strings including milliseconds.
A workaround is to remove the millisecond part with regular expression.
let isoDateString = "2017-01-23T10:12:31.484Z"let trimmedIsoString = isoDateString.replacingOccurrences(of: "\\.\\d+", with: "", options: .regularExpression)let formatter = ISO8601DateFormatter()let date = formatter.date(from: trimmedIsoString)
In macOS 10.13+ / iOS 11+ a new option is added to support fractional seconds:
static var withFractionalSeconds: ISO8601DateFormatter.Options { get }
let isoDateString = "2017-01-23T10:12:31.484Z"let formatter = ISO8601DateFormatter()formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]let date = formatter.date(from: isoDateString)
For people that are not ready to go to iOS 11 yet, you can always create your own formatter to handle milliseconds, e.g.:
extension DateFormatter { static var iSO8601DateWithMillisec: DateFormatter { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" return dateFormatter }}
Usage:
let formater = DateFormatter.iSO8601DateWithMilliseclet date = formater.date(from: "2017-01-23T10:12:31.484Z")!print(date) // output: 2017-01-23 10:12:31 +0000
It is slightly more elegant than writing a regex to strip out the milliseconds from the input string.
Maybe this will help to decode slightly different formats:
extension JSONDecoder { enum DateDecodeError: String, Error { case invalidDate } static var bestDateAttemptDecoder: JSONDecoder { let decoder = JSONDecoder() decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in let container = try decoder.singleValueContainer() if let dateSecs = try? container.decode(Double.self) { return Date(timeIntervalSince1970: dateSecs) } if let dateSecs = try? container.decode(UInt.self) { return Date(timeIntervalSince1970: TimeInterval(dateSecs)) } let dateStr = try container.decode(String.self) let isoFormatter = ISO8601DateFormatter() isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] if let date = isoFormatter.date(from: dateStr) { return date } isoFormatter.formatOptions = [.withInternetDateTime ] if let date = isoFormatter.date(from: dateStr) { return date } log.warning("Cannot decode date"); throw DateDecodeError.invalidDate }) return decoder }}
From: https://gist.github.com/th3m477/442a0d1da6354dd3b84e3b71df5dca6a