ISO8601DateFormatter doesn't parse ISO date string ISO8601DateFormatter doesn't parse ISO date string ios ios

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