How do I get an ISO 8601 date on iOS?
Use NSDateFormatter
:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
[dateFormatter setLocale:enUSPOSIXLocale];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];
[dateFormatter setCalendar:[NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian]];
NSDate *now = [NSDate date];
NSString *iso8601String = [dateFormatter stringFromDate:now];
And in Swift:
let dateFormatter = DateFormatter()
let enUSPosixLocale = Locale(identifier: "en_US_POSIX")
dateFormatter.locale = enUSPosixLocale
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
dateFormatter.calendar = Calendar(identifier: .gregorian)
let iso8601String = dateFormatter.string(from: Date())
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.
Converting ISO8601 Date Format to local time (iOS)
2015-03-20T20:00:00-07:00
is 8pm Pacific Daylight Time.
If you're representing 1pm PDT, that's either
2015-03-20T13:00:00-07:00
or represent that in "Zulu" (i.e. GMT/UTC)
2015-03-20T20:00:00Z
When working with a web service, the latter is the common convention for ISO 8601 dates. Then, when you present it to the user, you present it to them in their local timezone (using a NSDateFormatter
with its default timeZone
setting.
Note, when using NSDateFormatter
to prepare ISO 8601 dates, you will want to ensure that you specify a locale
of en_US_POSIX
as outlined in Technical Q&A QA1480. When designing app for US audience this isn't critical, but it's best practice in case the user is not using a gregorian calendar on their device.
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"]
change date format iso-8601 to custom format
When you are decoding a Date
the decoder expects an UNIX timestamp (a Double
) by default, this is what the error message tells you.
However you can indeed decode an ISO8601 string as Date
if you add the decoder.dateDecodingStrategy = .iso8601
but this decodes only standard ISO8601 strings without milliseconds.
There are two options:
Add a
formatted
dateDecodingStrategy
with aDateFormatter
.let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(dateFormatter)
try decoder.decode(...Declare
timestamp
aslet timestamp: String
and convert the string back and forth with two formatters or two date formats in
dateString
.
Related Topics
How to Trap on Uiviewalertforunsatisfiableconstraints
Invalid Swift Support - Files Don't Match
In Swift, Array [String] Slicing Return Type Doesn't Seem to Be [String]
Iphone: Hide Uitableview Search Bar by Default
Loading an Image into Uiimage Asynchronously
Is Silent Remote Notifications Possible If User Has Disabled Push for the App
Nsxmlparser on iOS, How to Use It Given a Xml File
How to Fix "No Valid 'Aps-Environment' Entitlement String Found for Application" in Xcode 4.3
Nsurlsession: How to Increase Time Out for Url Requests
iOS 5 Twitter Framework: Tweeting Without User Input and Confirmation (Modal View Controller)
How to Test If a String Is Empty in Objective-C
Swift Filter Dictionary Error: Cannot Assign a Value of Type '[(_, _)]' to a Value of Type '[_:_]'
Uitextview That Expands to Text Using Auto Layout
How to Rotate Text for Uibutton and Uilabel in Swift
Apns (Apple Push Notification Service) Reliability