Parsing a ISO8601 String to Date in Swift
Your date format is incorrect, you need to take into account the milliseconds.
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let updatedAtStr = "2016-06-05T16:56:57.019+01:00"
let updatedAt = dateFormatter.date(from: updatedAtStr) // "Jun 5, 2016, 4:56 PM"
Just to clarify, the addition of .SSS
in the date format is what fixes the problem.
Swift ISO8601 format to Date
You can specify ISO8601 date formate to the NSDateFormatter to get Date:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMdd'T'HHmmssZ"
print(dateFormatter.date(from: dateString)) //2018-02-07 12:46:00 +0000
Swift: Converting ISO8601 to Date
As @Martin has mentioned in the comments your date doesn't have the fractional seconds at the end of the string.
Here's the right format:
df.dateFormat = "yyyy-MM-dd'T'HH:mm:SSxxxxx"
or remove the withFractionalSeconds
from formatOptions
array of isoDateFormatter
, like this:
isoDateFormatter.formatOptions = [
.withFullDate,
.withFullTime,
.withDashSeparatorInDate]
Update: As @Leo has mentioned in the comments the use of Z
for time zone's format is wrong here, it needs to be xxxxx
instead.
convert ISO8601 String to reformatted date string(Swift)
ISO8601 has several different options, including a timezone. It appears that by default the ISO8601DateFormatter
expects a timezone indicator in the string. You can disable this behaviour by using custom options like so:
let pulledDate = "2017-06-16T13:38:34.601767"
var dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = [.withYear, .withMonth, .withDay, .withTime, .withDashSeparatorInDate, .withColonSeparatorInTime]
let date = dateFormatter.date(from: pulledDate)
If you want to know what are the default options, just run this code in a playground:
let dateFormatter = ISO8601DateFormatter()
let options = dateFormatter.formatOptions
options.contains(.withYear)
options.contains(.withMonth)
options.contains(.withWeekOfYear)
options.contains(.withDay)
options.contains(.withTime)
options.contains(.withTimeZone)
options.contains(.withSpaceBetweenDateAndTime)
options.contains(.withDashSeparatorInDate)
options.contains(.withColonSeparatorInTime)
options.contains(.withColonSeparatorInTimeZone)
options.contains(.withFullDate)
options.contains(.withFullTime)
options.contains(.withInternetDateTime)
Of course, if your string doesn't contain a timezone, the date formatter will still interpret it in a timezone using its timeZone
property, which – according to the documentation – defaults to GMT.
Remember to change it before using the formatter if you want to interpret your date in a different timezone:
dateFormatter.timeZone = TimeZone(identifier: "Europe/Paris")
Parse ISO8601 in swift
You didn't set the timezone of the output date, so it's defaulting to your systems' timezone rather than UTC (which is what you were expecting).
How can I parse / create a date time stamp formatted with fractional seconds UTC timezone (ISO 8601, RFC 3339) in Swift?
Swift 4 • iOS 11.2.1 or later
extension ISO8601DateFormatter {
convenience init(_ formatOptions: Options) {
self.init()
self.formatOptions = formatOptions
}
}
extension Formatter {
static let iso8601withFractionalSeconds = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])
}
extension Date {
var iso8601withFractionalSeconds: String { return Formatter.iso8601withFractionalSeconds.string(from: self) }
}
extension String {
var iso8601withFractionalSeconds: Date? { return Formatter.iso8601withFractionalSeconds.date(from: self) }
}
Usage:
Date().description(with: .current) // Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
let dateString = Date().iso8601withFractionalSeconds // "2019-02-06T00:35:01.746Z"
if let date = dateString.iso8601withFractionalSeconds {
date.description(with: .current) // "Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
print(date.iso8601withFractionalSeconds) // "2019-02-06T00:35:01.746Z\n"
}
iOS 9 • Swift 3 or later
extension Formatter {
static let iso8601withFractionalSeconds: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
return formatter
}()
}
Codable Protocol
If you need to encode and decode this format when working with Codable
protocol you can create your own custom date encoding/decoding strategies:
extension JSONDecoder.DateDecodingStrategy {
static let iso8601withFractionalSeconds = custom {
let container = try $0.singleValueContainer()
let string = try container.decode(String.self)
guard let date = Formatter.iso8601withFractionalSeconds.date(from: string) else {
throw DecodingError.dataCorruptedError(in: container,
debugDescription: "Invalid date: " + string)
}
return date
}
}
and the encoding strategy
extension JSONEncoder.DateEncodingStrategy {
static let iso8601withFractionalSeconds = custom {
var container = $1.singleValueContainer()
try container.encode(Formatter.iso8601withFractionalSeconds.string(from: $0))
}
}
Playground Testing
let dates = [Date()] // ["Feb 8, 2019 at 9:48 PM"]
encoding
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601withFractionalSeconds
let data = try! encoder.encode(dates)
print(String(data: data, encoding: .utf8)!)
decoding
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 8, 2019 at 9:48 PM"]
Related Topics
Why in Swift We Cannot Adopt a Protocol Without Inheritance a Class from Nsobject
Value of Optional Type Cgfloat Not Unwrapped Error in Swift
Swiftui Customized Text Field in Osx
Swift: Optional Text in Optional Value
How to Add Kerning to a Textfield in Swiftui
How to Pass Variable Value to Outside of Urlsession Async - Swift 3
How to Create Enum with Raw Type of Cgpoint
Macos Menubar Application: Main Menu Not Being Displayed
In Swift, How to Get Memory Back to Normal After an Skscene Is Removed
How to Use Raycast Methods in Realitykit
What Does the '@' Symbol Mean in Swift
Make Property of Type and Also Conform to Protocol in Swift
Why Should Not Directly Extend Uiview or Uiviewcontroller
Why Does Swift Playground Shows Wrong Number of Executions
How to Create an Array of Functions
Missing Return in a Function Expected to Return 'Double'
In Swift, How to Have a Uiscrollview Subclass That Has an Internal and External Delegate