Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ISO8601DateFormatter doesn't parse ISO date string

I'm trying to parse this

2017-01-23T10:12:31.484Z

using native ISO8601DateFormatter class provided by iOS 10 but always fails. If the string not contains milliseconds, the Date object is created without problems.

I'm tried this and many options combination but always fails...

let formatter = ISO8601DateFormatter() formatter.timeZone = TimeZone(secondsFromGMT: 0) formatter.formatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withColonSeparatorInTimeZone, .withFullTime] 

Any idea? Thanks!

like image 854
mhergon Avatar asked Jan 25 '17 09:01

mhergon


People also ask

How do I read the ISO 8601 date format?

ISO 8601 represents date and time by starting with the year, followed by the month, the day, the hour, the minutes, seconds and milliseconds. For example, 2020-07-10 15:00:00.000, represents the 10th of July 2020 at 3 p.m. (in local time as there is no time zone offset specified—more on that below).

Is valid ISO date string?

Yes, it is valid.

Is ISO 8601 a string?

The toISOString() method returns a string in simplified extended ISO format (ISO 8601), which is always 24 or 27 characters long ( YYYY-MM-DDTHH:mm:ss. sssZ or ±YYYYYY-MM-DDTHH:mm:ss. sssZ , respectively). The timezone is always zero UTC offset, as denoted by the suffix Z .


2 Answers

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) 
like image 116
vadian Avatar answered Sep 28 '22 10:09

vadian


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.iSO8601DateWithMillisec let 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.

like image 27
Yuchen Avatar answered Sep 28 '22 12:09

Yuchen