How to create a date time stamp and format as ISO 8601, RFC 3339, UTC time zone?












145















How to generate a date time stamp, using the format standards for ISO 8601 and RFC 3339?



The goal is a string that looks like this:



"2015-01-01T00:00:00.000Z"


Format:




  • year, month, day, as "XXXX-XX-XX"

  • the letter "T" as a separator

  • hour, minute, seconds, milliseconds, as "XX:XX:XX.XXX".

  • the letter "Z" as a zone designator for zero offset, a.k.a. UTC, GMT, Zulu time.


Best case:




  • Swift source code that is simple, short, and straightforward.

  • No need to use any additional framework, subproject, cocoapod, C code, etc.


I've searched StackOverflow, Google, Apple, etc. and haven't found a Swift answer to this.



The classes that seem most promising are NSDate, NSDateFormatter, NSTimeZone.



Related Q&A: How do I get ISO 8601 date in iOS?



Here's the best I've come up with so far:



var now = NSDate()
var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
println(formatter.stringFromDate(now))









share|improve this question




















  • 5





    Note that iOS10+ SIMPLY INCLUDES ISO 8601 BUILT-IN .. it will just autocomplete for you.

    – Fattie
    Apr 27 '17 at 12:46






  • 2





    @Fattie And - how can it handle that last .234Z milliseconds Zulu/UTC part of the timestamp? Answer: Matt Longs @ stackoverflow.com/a/42101630/3078330

    – smat88dd
    Jun 9 '17 at 12:30








  • 1





    @smat88dd -- fantastic tip, thanks. I had no clue there were "options on a formatter", weird and wild!

    – Fattie
    Jun 9 '17 at 17:03











  • I'm looking for a solution that works on linux.

    – neoneye
    Sep 20 '18 at 14:23











  • @neoneye Just use the old version (plain DateFormatter) and change the calendar iso8601 to gregorian stackoverflow.com/a/28016692/2303865

    – Leo Dabus
    Oct 31 '18 at 12:38


















145















How to generate a date time stamp, using the format standards for ISO 8601 and RFC 3339?



The goal is a string that looks like this:



"2015-01-01T00:00:00.000Z"


Format:




  • year, month, day, as "XXXX-XX-XX"

  • the letter "T" as a separator

  • hour, minute, seconds, milliseconds, as "XX:XX:XX.XXX".

  • the letter "Z" as a zone designator for zero offset, a.k.a. UTC, GMT, Zulu time.


Best case:




  • Swift source code that is simple, short, and straightforward.

  • No need to use any additional framework, subproject, cocoapod, C code, etc.


I've searched StackOverflow, Google, Apple, etc. and haven't found a Swift answer to this.



The classes that seem most promising are NSDate, NSDateFormatter, NSTimeZone.



Related Q&A: How do I get ISO 8601 date in iOS?



Here's the best I've come up with so far:



var now = NSDate()
var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
println(formatter.stringFromDate(now))









share|improve this question




















  • 5





    Note that iOS10+ SIMPLY INCLUDES ISO 8601 BUILT-IN .. it will just autocomplete for you.

    – Fattie
    Apr 27 '17 at 12:46






  • 2





    @Fattie And - how can it handle that last .234Z milliseconds Zulu/UTC part of the timestamp? Answer: Matt Longs @ stackoverflow.com/a/42101630/3078330

    – smat88dd
    Jun 9 '17 at 12:30








  • 1





    @smat88dd -- fantastic tip, thanks. I had no clue there were "options on a formatter", weird and wild!

    – Fattie
    Jun 9 '17 at 17:03











  • I'm looking for a solution that works on linux.

    – neoneye
    Sep 20 '18 at 14:23











  • @neoneye Just use the old version (plain DateFormatter) and change the calendar iso8601 to gregorian stackoverflow.com/a/28016692/2303865

    – Leo Dabus
    Oct 31 '18 at 12:38
















145












145








145


72






How to generate a date time stamp, using the format standards for ISO 8601 and RFC 3339?



The goal is a string that looks like this:



"2015-01-01T00:00:00.000Z"


Format:




  • year, month, day, as "XXXX-XX-XX"

  • the letter "T" as a separator

  • hour, minute, seconds, milliseconds, as "XX:XX:XX.XXX".

  • the letter "Z" as a zone designator for zero offset, a.k.a. UTC, GMT, Zulu time.


Best case:




  • Swift source code that is simple, short, and straightforward.

  • No need to use any additional framework, subproject, cocoapod, C code, etc.


I've searched StackOverflow, Google, Apple, etc. and haven't found a Swift answer to this.



The classes that seem most promising are NSDate, NSDateFormatter, NSTimeZone.



Related Q&A: How do I get ISO 8601 date in iOS?



Here's the best I've come up with so far:



var now = NSDate()
var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
println(formatter.stringFromDate(now))









share|improve this question
















How to generate a date time stamp, using the format standards for ISO 8601 and RFC 3339?



The goal is a string that looks like this:



"2015-01-01T00:00:00.000Z"


Format:




  • year, month, day, as "XXXX-XX-XX"

  • the letter "T" as a separator

  • hour, minute, seconds, milliseconds, as "XX:XX:XX.XXX".

  • the letter "Z" as a zone designator for zero offset, a.k.a. UTC, GMT, Zulu time.


Best case:




  • Swift source code that is simple, short, and straightforward.

  • No need to use any additional framework, subproject, cocoapod, C code, etc.


I've searched StackOverflow, Google, Apple, etc. and haven't found a Swift answer to this.



The classes that seem most promising are NSDate, NSDateFormatter, NSTimeZone.



Related Q&A: How do I get ISO 8601 date in iOS?



Here's the best I've come up with so far:



var now = NSDate()
var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
println(formatter.stringFromDate(now))






date swift time iso8601 rfc3339






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 24 '18 at 14:41









Rob

302k49564734




302k49564734










asked Jan 19 '15 at 0:58









joelparkerhendersonjoelparkerhenderson

26.6k1882106




26.6k1882106








  • 5





    Note that iOS10+ SIMPLY INCLUDES ISO 8601 BUILT-IN .. it will just autocomplete for you.

    – Fattie
    Apr 27 '17 at 12:46






  • 2





    @Fattie And - how can it handle that last .234Z milliseconds Zulu/UTC part of the timestamp? Answer: Matt Longs @ stackoverflow.com/a/42101630/3078330

    – smat88dd
    Jun 9 '17 at 12:30








  • 1





    @smat88dd -- fantastic tip, thanks. I had no clue there were "options on a formatter", weird and wild!

    – Fattie
    Jun 9 '17 at 17:03











  • I'm looking for a solution that works on linux.

    – neoneye
    Sep 20 '18 at 14:23











  • @neoneye Just use the old version (plain DateFormatter) and change the calendar iso8601 to gregorian stackoverflow.com/a/28016692/2303865

    – Leo Dabus
    Oct 31 '18 at 12:38
















  • 5





    Note that iOS10+ SIMPLY INCLUDES ISO 8601 BUILT-IN .. it will just autocomplete for you.

    – Fattie
    Apr 27 '17 at 12:46






  • 2





    @Fattie And - how can it handle that last .234Z milliseconds Zulu/UTC part of the timestamp? Answer: Matt Longs @ stackoverflow.com/a/42101630/3078330

    – smat88dd
    Jun 9 '17 at 12:30








  • 1





    @smat88dd -- fantastic tip, thanks. I had no clue there were "options on a formatter", weird and wild!

    – Fattie
    Jun 9 '17 at 17:03











  • I'm looking for a solution that works on linux.

    – neoneye
    Sep 20 '18 at 14:23











  • @neoneye Just use the old version (plain DateFormatter) and change the calendar iso8601 to gregorian stackoverflow.com/a/28016692/2303865

    – Leo Dabus
    Oct 31 '18 at 12:38










5




5





Note that iOS10+ SIMPLY INCLUDES ISO 8601 BUILT-IN .. it will just autocomplete for you.

– Fattie
Apr 27 '17 at 12:46





Note that iOS10+ SIMPLY INCLUDES ISO 8601 BUILT-IN .. it will just autocomplete for you.

– Fattie
Apr 27 '17 at 12:46




2




2





@Fattie And - how can it handle that last .234Z milliseconds Zulu/UTC part of the timestamp? Answer: Matt Longs @ stackoverflow.com/a/42101630/3078330

– smat88dd
Jun 9 '17 at 12:30







@Fattie And - how can it handle that last .234Z milliseconds Zulu/UTC part of the timestamp? Answer: Matt Longs @ stackoverflow.com/a/42101630/3078330

– smat88dd
Jun 9 '17 at 12:30






1




1





@smat88dd -- fantastic tip, thanks. I had no clue there were "options on a formatter", weird and wild!

– Fattie
Jun 9 '17 at 17:03





@smat88dd -- fantastic tip, thanks. I had no clue there were "options on a formatter", weird and wild!

– Fattie
Jun 9 '17 at 17:03













I'm looking for a solution that works on linux.

– neoneye
Sep 20 '18 at 14:23





I'm looking for a solution that works on linux.

– neoneye
Sep 20 '18 at 14:23













@neoneye Just use the old version (plain DateFormatter) and change the calendar iso8601 to gregorian stackoverflow.com/a/28016692/2303865

– Leo Dabus
Oct 31 '18 at 12:38







@neoneye Just use the old version (plain DateFormatter) and change the calendar iso8601 to gregorian stackoverflow.com/a/28016692/2303865

– Leo Dabus
Oct 31 '18 at 12:38














10 Answers
10






active

oldest

votes


















315














Xcode 9 • Swift 4 • iOS 11 or later



extension ISO8601DateFormatter {
convenience init(_ formatOptions: Options, timeZone: TimeZone = TimeZone(secondsFromGMT: 0)!) {
self.init()
self.formatOptions = formatOptions
self.timeZone = timeZone
}
}




extension Formatter {
static let iso8601 = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])
}




extension Date {
var iso8601: String {
return Formatter.iso8601.string(from: self)
}
}




extension String {
var iso8601: Date? {
return Formatter.iso8601.date(from: self)
}
}




Usage:



Date().description(with: .current)  //  Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
let dateString = Date().iso8601 // "2019-02-06T00:35:01.746Z"

if let date = dateString.iso8601 {
date.description(with: .current) // "Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
print(date.iso8601) // "2019-02-06T00:35:01.746Zn"
}




iOS 9 • Swift 3 or later



extension Formatter {
static let iso8601: 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.iso8601.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.iso8601.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)
String(data: data, encoding: .utf8)! // ["2019-02-08T23:46:12.985Z"]n"


decoding



let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 8, 2019 at 9:48 PM"]


enter image description here






share|improve this answer





















  • 3





    It'd be useful to add opposite conversion extension: extension String { var dateFormattedISO8601: NSDate? {return NSDate.Date.formatterISO8601.dateFromString(self)} }

    – Vive
    May 30 '16 at 10:50






  • 1





    Just an note that this looses a bit of precision so it's important to make sure equality of dates is compared via the generated string and not timeInterval. let now = NSDate() let stringFromDate = now.iso8601 let dateFromString = stringFromDate.dateFromISO8601! XCTAssertEqual(now.timeIntervalSince1970, dateFromString.timeIntervalSince1970)

    – pixelrevision
    Jun 18 '16 at 16:59






  • 7





    Needless to say, if you don't need milliseconds, the new iOS 10 ISO8601DateFormatter simplifies the process. I've issued a bug report (27242248) to Apple, requesting them to expand this new formatter to offer the ability to specify milliseconds, too (as this new formatter is not of use for many of us without the milliseconds).

    – Rob
    Jul 15 '16 at 22:28






  • 2





    @manRo "yyyy-MM-dd HH:mm:ssXXXXX"

    – Leo Dabus
    Oct 14 '16 at 2:22






  • 3





    @LeoDabus yes, but this is the first result for "Swift iso8601". My comment was meant to warn other developers who come across this in the future and was not directed at OP.

    – thislooksfun
    Jul 5 '17 at 1:10



















24














Remember to set the locale to en_US_POSIX as described in Technical Q&A1480. In Swift 3:



let date = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
print(formatter.string(from: date))


The issue is that if you're on a device which is using a non-Gregorian calendar, the year will not conform to RFC3339/ISO8601 unless you specify the locale as well as the timeZone and dateFormat string.



Or you can use ISO8601DateFormatter to get you out of the weeds of setting locale and timeZone yourself:



let date = Date()
let formatter = ISO8601DateFormatter()
formatter.formatOptions.insert(.withFractionalSeconds) // this is only available effective iOS 11 and macOS 10.13
print(formatter.string(from: date))


For Swift 2 rendition, see previous revision of this answer.






share|improve this answer


























  • why we should set the locale to en_US_POSIX ? even if we are not in US ?

    – mnemonic23
    Dec 13 '17 at 4:38






  • 1





    Well, you need some consistent locale and the convention of the ISO 8601/RFC 3999 standards is that format offered by en_US_POSIX. It's the lingua franca for exchanging dates on the web. And you can't have it misinterpreting dates if one calendar was used on device when saving a date string and another when the string is read back in later. Also, you need a format that is guaranteed to never change (which is why you use en_US_POSIX and not en_US). See Technical Q&A 1480 or those RFC/ISO standards for more information.

    – Rob
    Dec 13 '17 at 10:23





















19














If you want to use the ISO8601DateFormatter() with a date from a Rails 4+ JSON feed (and don't need millis of course), you need to set a few options on the formatter for it to work right otherwise the the date(from: string) function will return nil. Here's what I'm using:



extension Date {
init(dateString:String) {
self = Date.iso8601Formatter.date(from: dateString)!
}

static let iso8601Formatter: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withFullDate,
.withTime,
.withDashSeparatorInDate,
.withColonSeparatorInTime]
return formatter
}()
}


Here's the result of using the options verses not in a playground screenshot:



enter image description here






share|improve this answer
























  • You would need to include in the options also the .withFractionalSeconds but I already tried that and it keeps throwing an error libc++abi.dylib: terminating with uncaught exception of type NSException.

    – Leo Dabus
    Oct 12 '17 at 1:36











  • @MEnnabah It works fine for me in Swift 4. Are you getting an error?

    – Matt Long
    Nov 6 '17 at 16:22











  • @LeoDabus, got the same error as yours, did you solve it?

    – freeman
    Dec 13 '17 at 3:36













  • custom JSONDecoder DateDecodingStrategy stackoverflow.com/a/46458771/2303865

    – Leo Dabus
    Dec 13 '17 at 3:40













  • @freeman If you would like to preserve the Date with all its fractional seconds I suggest to use a double (time interval since reference date) when saving/receiving your date to the server. And use the default date decoding strategy .deferredToDate when using Codable protocol

    – Leo Dabus
    Dec 13 '17 at 3:47





















4














To further compliment Andrés Torres Marroquín and Leo Dabus, I have a version that preserves fractional seconds. I can't find it documented anywhere, but Apple truncate fractional seconds to the microsecond (3 digits of precision) on both input and output (even though specified using SSSSSSS, contrary to Unicode tr35-31).



I should stress that this is probably not necessary for most use cases. Dates online do not typically need millisecond precision, and when they do, it is often better to use a different data format. But sometimes one must interoperate with a pre-existing system in a particular way.



Xcode 8/9 and Swift 3.0-3.2



extension Date {
struct Formatter {
static let iso8601: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(identifier: "UTC")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX"
return formatter
}()
}

var iso8601: String {
// create base Date format
var formatted = DateFormatter.iso8601.string(from: self)

// Apple returns millisecond precision. find the range of the decimal portion
if let fractionStart = formatted.range(of: "."),
let fractionEnd = formatted.index(fractionStart.lowerBound, offsetBy: 7, limitedBy: formatted.endIndex) {
let fractionRange = fractionStart.lowerBound..<fractionEnd
// replace the decimal range with our own 6 digit fraction output
let microseconds = self.timeIntervalSince1970 - floor(self.timeIntervalSince1970)
var microsecondsStr = String(format: "%.06f", microseconds)
microsecondsStr.remove(at: microsecondsStr.startIndex)
formatted.replaceSubrange(fractionRange, with: microsecondsStr)
}
return formatted
}
}

extension String {
var dateFromISO8601: Date? {
guard let parsedDate = Date.Formatter.iso8601.date(from: self) else {
return nil
}

var preliminaryDate = Date(timeIntervalSinceReferenceDate: floor(parsedDate.timeIntervalSinceReferenceDate))

if let fractionStart = self.range(of: "."),
let fractionEnd = self.index(fractionStart.lowerBound, offsetBy: 7, limitedBy: self.endIndex) {
let fractionRange = fractionStart.lowerBound..<fractionEnd
let fractionStr = self.substring(with: fractionRange)

if var fraction = Double(fractionStr) {
fraction = Double(floor(1000000*fraction)/1000000)
preliminaryDate.addTimeInterval(fraction)
}
}
return preliminaryDate
}
}





share|improve this answer


























  • This is the best answer in my opinion in that it allows one to get to a microsecond level of precision where all the other solutions truncate at milliseconds.

    – Michael A. McCloskey
    Sep 29 '17 at 19:31











  • If you would like to preserve the Date with all its fractional seconds you should use just a double (time interval since reference date) when saving/receiving your date to the server.

    – Leo Dabus
    Dec 13 '17 at 3:45











  • @LeoDabus yes, if you control the whole system and don't need to interoperate. Like I said in the answer, this isn't necessary for most users. But we don't all always have control over the data formatting in web APIs, and as Android and Python (at least) preserve 6 digits of fractional precision, it is sometimes necessary to follow suit.

    – Eli Burke
    Dec 14 '17 at 14:57



















3














In my case I have to convert the DynamoDB - lastUpdated column (Unix Timestamp) to Normal Time.



The initial value of lastUpdated was : 1460650607601 - converted down to 2016-04-14 16:16:47 +0000 via :



   if let lastUpdated : String = userObject.lastUpdated {

let epocTime = NSTimeInterval(lastUpdated)! / 1000 // convert it from milliseconds dividing it by 1000

let unixTimestamp = NSDate(timeIntervalSince1970: epocTime) //convert unix timestamp to Date
let dateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone()
dateFormatter.locale = NSLocale.currentLocale() // NSLocale(localeIdentifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
dateFormatter.dateFromString(String(unixTimestamp))

let updatedTimeStamp = unixTimestamp
print(updatedTimeStamp)

}





share|improve this answer































    3














    In the future the format might need to be changed which could be a small head ache having date.dateFromISO8601 calls everywhere in an app. Use a class and protocol to wrap the implementation, changing the date time format call in one place will be simpler. Use RFC3339 if possible, its a more complete representation. DateFormatProtocol and DateFormat is great for dependency injection.



    class AppDelegate: UIResponder, UIApplicationDelegate {

    internal static let rfc3339DateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
    internal static let localeEnUsPosix = "en_US_POSIX"
    }

    import Foundation

    protocol DateFormatProtocol {

    func format(date: NSDate) -> String
    func parse(date: String) -> NSDate?

    }


    import Foundation

    class DateFormat: DateFormatProtocol {

    func format(date: NSDate) -> String {
    return date.rfc3339
    }

    func parse(date: String) -> NSDate? {
    return date.rfc3339
    }

    }


    extension NSDate {

    struct Formatter {
    static let rfc3339: NSDateFormatter = {
    let formatter = NSDateFormatter()
    formatter.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601)
    formatter.locale = NSLocale(localeIdentifier: AppDelegate.localeEnUsPosix)
    formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
    formatter.dateFormat = rfc3339DateFormat
    return formatter
    }()
    }

    var rfc3339: String { return Formatter.rfc3339.stringFromDate(self) }
    }

    extension String {
    var rfc3339: NSDate? {
    return NSDate.Formatter.rfc3339.dateFromString(self)
    }
    }



    class DependencyService: DependencyServiceProtocol {

    private var dateFormat: DateFormatProtocol?

    func setDateFormat(dateFormat: DateFormatProtocol) {
    self.dateFormat = dateFormat
    }

    func getDateFormat() -> DateFormatProtocol {
    if let dateFormatObject = dateFormat {

    return dateFormatObject
    } else {
    let dateFormatObject = DateFormat()
    dateFormat = dateFormatObject

    return dateFormatObject
    }
    }

    }





    share|improve this answer

































      3














      There is a new ISO8601DateFormatter class that let's you create a string with just one line. For backwards compatibility I used an old C-library. I hope this is useful for someone.



      Swift 3.0



      extension Date {
      var iso8601: String {
      if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
      return ISO8601DateFormatter.string(from: self, timeZone: TimeZone.current, formatOptions: .withInternetDateTime)
      } else {
      var buffer = [CChar](repeating: 0, count: 25)
      var time = time_t(self.timeIntervalSince1970)
      strftime_l(&buffer, buffer.count, "%FT%T%z", localtime(&time), nil)
      return String(cString: buffer)
      }
      }
      }





      share|improve this answer































        2














        Uses ISO8601DateFormatter on iOS10 or newer.



        Uses DateFormatter on iOS9 or older.



        Swift 4



        protocol DateFormatterProtocol {
        func string(from date: Date) -> String
        func date(from string: String) -> Date?
        }

        extension DateFormatter: DateFormatterProtocol {}

        @available(iOS 10.0, *)
        extension ISO8601DateFormatter: DateFormatterProtocol {}

        struct DateFormatterShared {
        static let iso8601: DateFormatterProtocol = {
        if #available(iOS 10, *) {
        return ISO8601DateFormatter()
        } else {
        // iOS 9
        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
        }
        }()
        }





        share|improve this answer































          0














          To complement the version of Leo Dabus, I added support for projects written Swift and Objective-C, also added support for the optional milliseconds, probably isn't the best but you would get the point:



          Xcode 8 and Swift 3



          extension Date {
          struct Formatter {
          static let iso8601: 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
          }()
          }

          var iso8601: String {
          return Formatter.iso8601.string(from: self)
          }
          }


          extension String {
          var dateFromISO8601: Date? {
          var data = self
          if self.range(of: ".") == nil {
          // Case where the string doesn't contain the optional milliseconds
          data = data.replacingOccurrences(of: "Z", with: ".000000Z")
          }
          return Date.Formatter.iso8601.date(from: data)
          }
          }


          extension NSString {
          var dateFromISO8601: Date? {
          return (self as String).dateFromISO8601
          }
          }





          share|improve this answer































            0














            Without some manual String masks or TimeFormatters



            import Foundation

            struct DateISO: Codable {
            var date: Date
            }

            extension Date{
            var isoString: String {
            let encoder = JSONEncoder()
            encoder.dateEncodingStrategy = .iso8601
            guard let data = try? encoder.encode(DateISO(date: self)),
            let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: String]
            else { return "" }
            return json?.first?.value ?? ""
            }
            }

            let dateString = Date().isoString





            share|improve this answer
























            • Note that this will create a JSONEncoder object every time you call this property. FYI options: .allowFragments is pointless and can just be omitted. Btw your approach would be much easier if you encode your date as a single element collection.

              – Leo Dabus
              Feb 6 at 11:17











            • extension JSONEncoder { static let iso8601: JSONEncoder = { let iso8601 = JSONEncoder() iso8601.dateEncodingStrategy = .iso8601 return iso8601 }() } extension Date { var isoString: String { return (try! JSONSerialization.jsonObject(with: JSONEncoder.iso8601.encode([self])) as! [String]).first! } } and don't worry about forcing unwrap, it will never fail in this case.

              – Leo Dabus
              Feb 6 at 11:18













            • Another option when using the array approach is to drop the first and last 2 bytes of the encoded data and convert the subdata to string. extension Date { var isoString: String { return try! String(data: JSONEncoder.iso8601.encode([self])[2..<22], encoding: .utf8)! } }

              – Leo Dabus
              Feb 6 at 11:49













            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f28016578%2fhow-to-create-a-date-time-stamp-and-format-as-iso-8601-rfc-3339-utc-time-zone%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            10 Answers
            10






            active

            oldest

            votes








            10 Answers
            10






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            315














            Xcode 9 • Swift 4 • iOS 11 or later



            extension ISO8601DateFormatter {
            convenience init(_ formatOptions: Options, timeZone: TimeZone = TimeZone(secondsFromGMT: 0)!) {
            self.init()
            self.formatOptions = formatOptions
            self.timeZone = timeZone
            }
            }




            extension Formatter {
            static let iso8601 = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])
            }




            extension Date {
            var iso8601: String {
            return Formatter.iso8601.string(from: self)
            }
            }




            extension String {
            var iso8601: Date? {
            return Formatter.iso8601.date(from: self)
            }
            }




            Usage:



            Date().description(with: .current)  //  Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
            let dateString = Date().iso8601 // "2019-02-06T00:35:01.746Z"

            if let date = dateString.iso8601 {
            date.description(with: .current) // "Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
            print(date.iso8601) // "2019-02-06T00:35:01.746Zn"
            }




            iOS 9 • Swift 3 or later



            extension Formatter {
            static let iso8601: 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.iso8601.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.iso8601.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)
            String(data: data, encoding: .utf8)! // ["2019-02-08T23:46:12.985Z"]n"


            decoding



            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
            let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 8, 2019 at 9:48 PM"]


            enter image description here






            share|improve this answer





















            • 3





              It'd be useful to add opposite conversion extension: extension String { var dateFormattedISO8601: NSDate? {return NSDate.Date.formatterISO8601.dateFromString(self)} }

              – Vive
              May 30 '16 at 10:50






            • 1





              Just an note that this looses a bit of precision so it's important to make sure equality of dates is compared via the generated string and not timeInterval. let now = NSDate() let stringFromDate = now.iso8601 let dateFromString = stringFromDate.dateFromISO8601! XCTAssertEqual(now.timeIntervalSince1970, dateFromString.timeIntervalSince1970)

              – pixelrevision
              Jun 18 '16 at 16:59






            • 7





              Needless to say, if you don't need milliseconds, the new iOS 10 ISO8601DateFormatter simplifies the process. I've issued a bug report (27242248) to Apple, requesting them to expand this new formatter to offer the ability to specify milliseconds, too (as this new formatter is not of use for many of us without the milliseconds).

              – Rob
              Jul 15 '16 at 22:28






            • 2





              @manRo "yyyy-MM-dd HH:mm:ssXXXXX"

              – Leo Dabus
              Oct 14 '16 at 2:22






            • 3





              @LeoDabus yes, but this is the first result for "Swift iso8601". My comment was meant to warn other developers who come across this in the future and was not directed at OP.

              – thislooksfun
              Jul 5 '17 at 1:10
















            315














            Xcode 9 • Swift 4 • iOS 11 or later



            extension ISO8601DateFormatter {
            convenience init(_ formatOptions: Options, timeZone: TimeZone = TimeZone(secondsFromGMT: 0)!) {
            self.init()
            self.formatOptions = formatOptions
            self.timeZone = timeZone
            }
            }




            extension Formatter {
            static let iso8601 = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])
            }




            extension Date {
            var iso8601: String {
            return Formatter.iso8601.string(from: self)
            }
            }




            extension String {
            var iso8601: Date? {
            return Formatter.iso8601.date(from: self)
            }
            }




            Usage:



            Date().description(with: .current)  //  Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
            let dateString = Date().iso8601 // "2019-02-06T00:35:01.746Z"

            if let date = dateString.iso8601 {
            date.description(with: .current) // "Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
            print(date.iso8601) // "2019-02-06T00:35:01.746Zn"
            }




            iOS 9 • Swift 3 or later



            extension Formatter {
            static let iso8601: 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.iso8601.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.iso8601.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)
            String(data: data, encoding: .utf8)! // ["2019-02-08T23:46:12.985Z"]n"


            decoding



            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
            let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 8, 2019 at 9:48 PM"]


            enter image description here






            share|improve this answer





















            • 3





              It'd be useful to add opposite conversion extension: extension String { var dateFormattedISO8601: NSDate? {return NSDate.Date.formatterISO8601.dateFromString(self)} }

              – Vive
              May 30 '16 at 10:50






            • 1





              Just an note that this looses a bit of precision so it's important to make sure equality of dates is compared via the generated string and not timeInterval. let now = NSDate() let stringFromDate = now.iso8601 let dateFromString = stringFromDate.dateFromISO8601! XCTAssertEqual(now.timeIntervalSince1970, dateFromString.timeIntervalSince1970)

              – pixelrevision
              Jun 18 '16 at 16:59






            • 7





              Needless to say, if you don't need milliseconds, the new iOS 10 ISO8601DateFormatter simplifies the process. I've issued a bug report (27242248) to Apple, requesting them to expand this new formatter to offer the ability to specify milliseconds, too (as this new formatter is not of use for many of us without the milliseconds).

              – Rob
              Jul 15 '16 at 22:28






            • 2





              @manRo "yyyy-MM-dd HH:mm:ssXXXXX"

              – Leo Dabus
              Oct 14 '16 at 2:22






            • 3





              @LeoDabus yes, but this is the first result for "Swift iso8601". My comment was meant to warn other developers who come across this in the future and was not directed at OP.

              – thislooksfun
              Jul 5 '17 at 1:10














            315












            315








            315







            Xcode 9 • Swift 4 • iOS 11 or later



            extension ISO8601DateFormatter {
            convenience init(_ formatOptions: Options, timeZone: TimeZone = TimeZone(secondsFromGMT: 0)!) {
            self.init()
            self.formatOptions = formatOptions
            self.timeZone = timeZone
            }
            }




            extension Formatter {
            static let iso8601 = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])
            }




            extension Date {
            var iso8601: String {
            return Formatter.iso8601.string(from: self)
            }
            }




            extension String {
            var iso8601: Date? {
            return Formatter.iso8601.date(from: self)
            }
            }




            Usage:



            Date().description(with: .current)  //  Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
            let dateString = Date().iso8601 // "2019-02-06T00:35:01.746Z"

            if let date = dateString.iso8601 {
            date.description(with: .current) // "Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
            print(date.iso8601) // "2019-02-06T00:35:01.746Zn"
            }




            iOS 9 • Swift 3 or later



            extension Formatter {
            static let iso8601: 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.iso8601.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.iso8601.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)
            String(data: data, encoding: .utf8)! // ["2019-02-08T23:46:12.985Z"]n"


            decoding



            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
            let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 8, 2019 at 9:48 PM"]


            enter image description here






            share|improve this answer















            Xcode 9 • Swift 4 • iOS 11 or later



            extension ISO8601DateFormatter {
            convenience init(_ formatOptions: Options, timeZone: TimeZone = TimeZone(secondsFromGMT: 0)!) {
            self.init()
            self.formatOptions = formatOptions
            self.timeZone = timeZone
            }
            }




            extension Formatter {
            static let iso8601 = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])
            }




            extension Date {
            var iso8601: String {
            return Formatter.iso8601.string(from: self)
            }
            }




            extension String {
            var iso8601: Date? {
            return Formatter.iso8601.date(from: self)
            }
            }




            Usage:



            Date().description(with: .current)  //  Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
            let dateString = Date().iso8601 // "2019-02-06T00:35:01.746Z"

            if let date = dateString.iso8601 {
            date.description(with: .current) // "Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
            print(date.iso8601) // "2019-02-06T00:35:01.746Zn"
            }




            iOS 9 • Swift 3 or later



            extension Formatter {
            static let iso8601: 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.iso8601.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.iso8601.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)
            String(data: data, encoding: .utf8)! // ["2019-02-08T23:46:12.985Z"]n"


            decoding



            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
            let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 8, 2019 at 9:48 PM"]


            enter image description here







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Feb 9 at 0:06

























            answered Jan 19 '15 at 1:18









            Leo DabusLeo Dabus

            135k32277351




            135k32277351








            • 3





              It'd be useful to add opposite conversion extension: extension String { var dateFormattedISO8601: NSDate? {return NSDate.Date.formatterISO8601.dateFromString(self)} }

              – Vive
              May 30 '16 at 10:50






            • 1





              Just an note that this looses a bit of precision so it's important to make sure equality of dates is compared via the generated string and not timeInterval. let now = NSDate() let stringFromDate = now.iso8601 let dateFromString = stringFromDate.dateFromISO8601! XCTAssertEqual(now.timeIntervalSince1970, dateFromString.timeIntervalSince1970)

              – pixelrevision
              Jun 18 '16 at 16:59






            • 7





              Needless to say, if you don't need milliseconds, the new iOS 10 ISO8601DateFormatter simplifies the process. I've issued a bug report (27242248) to Apple, requesting them to expand this new formatter to offer the ability to specify milliseconds, too (as this new formatter is not of use for many of us without the milliseconds).

              – Rob
              Jul 15 '16 at 22:28






            • 2





              @manRo "yyyy-MM-dd HH:mm:ssXXXXX"

              – Leo Dabus
              Oct 14 '16 at 2:22






            • 3





              @LeoDabus yes, but this is the first result for "Swift iso8601". My comment was meant to warn other developers who come across this in the future and was not directed at OP.

              – thislooksfun
              Jul 5 '17 at 1:10














            • 3





              It'd be useful to add opposite conversion extension: extension String { var dateFormattedISO8601: NSDate? {return NSDate.Date.formatterISO8601.dateFromString(self)} }

              – Vive
              May 30 '16 at 10:50






            • 1





              Just an note that this looses a bit of precision so it's important to make sure equality of dates is compared via the generated string and not timeInterval. let now = NSDate() let stringFromDate = now.iso8601 let dateFromString = stringFromDate.dateFromISO8601! XCTAssertEqual(now.timeIntervalSince1970, dateFromString.timeIntervalSince1970)

              – pixelrevision
              Jun 18 '16 at 16:59






            • 7





              Needless to say, if you don't need milliseconds, the new iOS 10 ISO8601DateFormatter simplifies the process. I've issued a bug report (27242248) to Apple, requesting them to expand this new formatter to offer the ability to specify milliseconds, too (as this new formatter is not of use for many of us without the milliseconds).

              – Rob
              Jul 15 '16 at 22:28






            • 2





              @manRo "yyyy-MM-dd HH:mm:ssXXXXX"

              – Leo Dabus
              Oct 14 '16 at 2:22






            • 3





              @LeoDabus yes, but this is the first result for "Swift iso8601". My comment was meant to warn other developers who come across this in the future and was not directed at OP.

              – thislooksfun
              Jul 5 '17 at 1:10








            3




            3





            It'd be useful to add opposite conversion extension: extension String { var dateFormattedISO8601: NSDate? {return NSDate.Date.formatterISO8601.dateFromString(self)} }

            – Vive
            May 30 '16 at 10:50





            It'd be useful to add opposite conversion extension: extension String { var dateFormattedISO8601: NSDate? {return NSDate.Date.formatterISO8601.dateFromString(self)} }

            – Vive
            May 30 '16 at 10:50




            1




            1





            Just an note that this looses a bit of precision so it's important to make sure equality of dates is compared via the generated string and not timeInterval. let now = NSDate() let stringFromDate = now.iso8601 let dateFromString = stringFromDate.dateFromISO8601! XCTAssertEqual(now.timeIntervalSince1970, dateFromString.timeIntervalSince1970)

            – pixelrevision
            Jun 18 '16 at 16:59





            Just an note that this looses a bit of precision so it's important to make sure equality of dates is compared via the generated string and not timeInterval. let now = NSDate() let stringFromDate = now.iso8601 let dateFromString = stringFromDate.dateFromISO8601! XCTAssertEqual(now.timeIntervalSince1970, dateFromString.timeIntervalSince1970)

            – pixelrevision
            Jun 18 '16 at 16:59




            7




            7





            Needless to say, if you don't need milliseconds, the new iOS 10 ISO8601DateFormatter simplifies the process. I've issued a bug report (27242248) to Apple, requesting them to expand this new formatter to offer the ability to specify milliseconds, too (as this new formatter is not of use for many of us without the milliseconds).

            – Rob
            Jul 15 '16 at 22:28





            Needless to say, if you don't need milliseconds, the new iOS 10 ISO8601DateFormatter simplifies the process. I've issued a bug report (27242248) to Apple, requesting them to expand this new formatter to offer the ability to specify milliseconds, too (as this new formatter is not of use for many of us without the milliseconds).

            – Rob
            Jul 15 '16 at 22:28




            2




            2





            @manRo "yyyy-MM-dd HH:mm:ssXXXXX"

            – Leo Dabus
            Oct 14 '16 at 2:22





            @manRo "yyyy-MM-dd HH:mm:ssXXXXX"

            – Leo Dabus
            Oct 14 '16 at 2:22




            3




            3





            @LeoDabus yes, but this is the first result for "Swift iso8601". My comment was meant to warn other developers who come across this in the future and was not directed at OP.

            – thislooksfun
            Jul 5 '17 at 1:10





            @LeoDabus yes, but this is the first result for "Swift iso8601". My comment was meant to warn other developers who come across this in the future and was not directed at OP.

            – thislooksfun
            Jul 5 '17 at 1:10













            24














            Remember to set the locale to en_US_POSIX as described in Technical Q&A1480. In Swift 3:



            let date = Date()
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
            formatter.timeZone = TimeZone(secondsFromGMT: 0)
            formatter.locale = Locale(identifier: "en_US_POSIX")
            print(formatter.string(from: date))


            The issue is that if you're on a device which is using a non-Gregorian calendar, the year will not conform to RFC3339/ISO8601 unless you specify the locale as well as the timeZone and dateFormat string.



            Or you can use ISO8601DateFormatter to get you out of the weeds of setting locale and timeZone yourself:



            let date = Date()
            let formatter = ISO8601DateFormatter()
            formatter.formatOptions.insert(.withFractionalSeconds) // this is only available effective iOS 11 and macOS 10.13
            print(formatter.string(from: date))


            For Swift 2 rendition, see previous revision of this answer.






            share|improve this answer


























            • why we should set the locale to en_US_POSIX ? even if we are not in US ?

              – mnemonic23
              Dec 13 '17 at 4:38






            • 1





              Well, you need some consistent locale and the convention of the ISO 8601/RFC 3999 standards is that format offered by en_US_POSIX. It's the lingua franca for exchanging dates on the web. And you can't have it misinterpreting dates if one calendar was used on device when saving a date string and another when the string is read back in later. Also, you need a format that is guaranteed to never change (which is why you use en_US_POSIX and not en_US). See Technical Q&A 1480 or those RFC/ISO standards for more information.

              – Rob
              Dec 13 '17 at 10:23


















            24














            Remember to set the locale to en_US_POSIX as described in Technical Q&A1480. In Swift 3:



            let date = Date()
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
            formatter.timeZone = TimeZone(secondsFromGMT: 0)
            formatter.locale = Locale(identifier: "en_US_POSIX")
            print(formatter.string(from: date))


            The issue is that if you're on a device which is using a non-Gregorian calendar, the year will not conform to RFC3339/ISO8601 unless you specify the locale as well as the timeZone and dateFormat string.



            Or you can use ISO8601DateFormatter to get you out of the weeds of setting locale and timeZone yourself:



            let date = Date()
            let formatter = ISO8601DateFormatter()
            formatter.formatOptions.insert(.withFractionalSeconds) // this is only available effective iOS 11 and macOS 10.13
            print(formatter.string(from: date))


            For Swift 2 rendition, see previous revision of this answer.






            share|improve this answer


























            • why we should set the locale to en_US_POSIX ? even if we are not in US ?

              – mnemonic23
              Dec 13 '17 at 4:38






            • 1





              Well, you need some consistent locale and the convention of the ISO 8601/RFC 3999 standards is that format offered by en_US_POSIX. It's the lingua franca for exchanging dates on the web. And you can't have it misinterpreting dates if one calendar was used on device when saving a date string and another when the string is read back in later. Also, you need a format that is guaranteed to never change (which is why you use en_US_POSIX and not en_US). See Technical Q&A 1480 or those RFC/ISO standards for more information.

              – Rob
              Dec 13 '17 at 10:23
















            24












            24








            24







            Remember to set the locale to en_US_POSIX as described in Technical Q&A1480. In Swift 3:



            let date = Date()
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
            formatter.timeZone = TimeZone(secondsFromGMT: 0)
            formatter.locale = Locale(identifier: "en_US_POSIX")
            print(formatter.string(from: date))


            The issue is that if you're on a device which is using a non-Gregorian calendar, the year will not conform to RFC3339/ISO8601 unless you specify the locale as well as the timeZone and dateFormat string.



            Or you can use ISO8601DateFormatter to get you out of the weeds of setting locale and timeZone yourself:



            let date = Date()
            let formatter = ISO8601DateFormatter()
            formatter.formatOptions.insert(.withFractionalSeconds) // this is only available effective iOS 11 and macOS 10.13
            print(formatter.string(from: date))


            For Swift 2 rendition, see previous revision of this answer.






            share|improve this answer















            Remember to set the locale to en_US_POSIX as described in Technical Q&A1480. In Swift 3:



            let date = Date()
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
            formatter.timeZone = TimeZone(secondsFromGMT: 0)
            formatter.locale = Locale(identifier: "en_US_POSIX")
            print(formatter.string(from: date))


            The issue is that if you're on a device which is using a non-Gregorian calendar, the year will not conform to RFC3339/ISO8601 unless you specify the locale as well as the timeZone and dateFormat string.



            Or you can use ISO8601DateFormatter to get you out of the weeds of setting locale and timeZone yourself:



            let date = Date()
            let formatter = ISO8601DateFormatter()
            formatter.formatOptions.insert(.withFractionalSeconds) // this is only available effective iOS 11 and macOS 10.13
            print(formatter.string(from: date))


            For Swift 2 rendition, see previous revision of this answer.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Dec 26 '17 at 20:45

























            answered Jan 19 '15 at 1:04









            RobRob

            302k49564734




            302k49564734













            • why we should set the locale to en_US_POSIX ? even if we are not in US ?

              – mnemonic23
              Dec 13 '17 at 4:38






            • 1





              Well, you need some consistent locale and the convention of the ISO 8601/RFC 3999 standards is that format offered by en_US_POSIX. It's the lingua franca for exchanging dates on the web. And you can't have it misinterpreting dates if one calendar was used on device when saving a date string and another when the string is read back in later. Also, you need a format that is guaranteed to never change (which is why you use en_US_POSIX and not en_US). See Technical Q&A 1480 or those RFC/ISO standards for more information.

              – Rob
              Dec 13 '17 at 10:23





















            • why we should set the locale to en_US_POSIX ? even if we are not in US ?

              – mnemonic23
              Dec 13 '17 at 4:38






            • 1





              Well, you need some consistent locale and the convention of the ISO 8601/RFC 3999 standards is that format offered by en_US_POSIX. It's the lingua franca for exchanging dates on the web. And you can't have it misinterpreting dates if one calendar was used on device when saving a date string and another when the string is read back in later. Also, you need a format that is guaranteed to never change (which is why you use en_US_POSIX and not en_US). See Technical Q&A 1480 or those RFC/ISO standards for more information.

              – Rob
              Dec 13 '17 at 10:23



















            why we should set the locale to en_US_POSIX ? even if we are not in US ?

            – mnemonic23
            Dec 13 '17 at 4:38





            why we should set the locale to en_US_POSIX ? even if we are not in US ?

            – mnemonic23
            Dec 13 '17 at 4:38




            1




            1





            Well, you need some consistent locale and the convention of the ISO 8601/RFC 3999 standards is that format offered by en_US_POSIX. It's the lingua franca for exchanging dates on the web. And you can't have it misinterpreting dates if one calendar was used on device when saving a date string and another when the string is read back in later. Also, you need a format that is guaranteed to never change (which is why you use en_US_POSIX and not en_US). See Technical Q&A 1480 or those RFC/ISO standards for more information.

            – Rob
            Dec 13 '17 at 10:23







            Well, you need some consistent locale and the convention of the ISO 8601/RFC 3999 standards is that format offered by en_US_POSIX. It's the lingua franca for exchanging dates on the web. And you can't have it misinterpreting dates if one calendar was used on device when saving a date string and another when the string is read back in later. Also, you need a format that is guaranteed to never change (which is why you use en_US_POSIX and not en_US). See Technical Q&A 1480 or those RFC/ISO standards for more information.

            – Rob
            Dec 13 '17 at 10:23













            19














            If you want to use the ISO8601DateFormatter() with a date from a Rails 4+ JSON feed (and don't need millis of course), you need to set a few options on the formatter for it to work right otherwise the the date(from: string) function will return nil. Here's what I'm using:



            extension Date {
            init(dateString:String) {
            self = Date.iso8601Formatter.date(from: dateString)!
            }

            static let iso8601Formatter: ISO8601DateFormatter = {
            let formatter = ISO8601DateFormatter()
            formatter.formatOptions = [.withFullDate,
            .withTime,
            .withDashSeparatorInDate,
            .withColonSeparatorInTime]
            return formatter
            }()
            }


            Here's the result of using the options verses not in a playground screenshot:



            enter image description here






            share|improve this answer
























            • You would need to include in the options also the .withFractionalSeconds but I already tried that and it keeps throwing an error libc++abi.dylib: terminating with uncaught exception of type NSException.

              – Leo Dabus
              Oct 12 '17 at 1:36











            • @MEnnabah It works fine for me in Swift 4. Are you getting an error?

              – Matt Long
              Nov 6 '17 at 16:22











            • @LeoDabus, got the same error as yours, did you solve it?

              – freeman
              Dec 13 '17 at 3:36













            • custom JSONDecoder DateDecodingStrategy stackoverflow.com/a/46458771/2303865

              – Leo Dabus
              Dec 13 '17 at 3:40













            • @freeman If you would like to preserve the Date with all its fractional seconds I suggest to use a double (time interval since reference date) when saving/receiving your date to the server. And use the default date decoding strategy .deferredToDate when using Codable protocol

              – Leo Dabus
              Dec 13 '17 at 3:47


















            19














            If you want to use the ISO8601DateFormatter() with a date from a Rails 4+ JSON feed (and don't need millis of course), you need to set a few options on the formatter for it to work right otherwise the the date(from: string) function will return nil. Here's what I'm using:



            extension Date {
            init(dateString:String) {
            self = Date.iso8601Formatter.date(from: dateString)!
            }

            static let iso8601Formatter: ISO8601DateFormatter = {
            let formatter = ISO8601DateFormatter()
            formatter.formatOptions = [.withFullDate,
            .withTime,
            .withDashSeparatorInDate,
            .withColonSeparatorInTime]
            return formatter
            }()
            }


            Here's the result of using the options verses not in a playground screenshot:



            enter image description here






            share|improve this answer
























            • You would need to include in the options also the .withFractionalSeconds but I already tried that and it keeps throwing an error libc++abi.dylib: terminating with uncaught exception of type NSException.

              – Leo Dabus
              Oct 12 '17 at 1:36











            • @MEnnabah It works fine for me in Swift 4. Are you getting an error?

              – Matt Long
              Nov 6 '17 at 16:22











            • @LeoDabus, got the same error as yours, did you solve it?

              – freeman
              Dec 13 '17 at 3:36













            • custom JSONDecoder DateDecodingStrategy stackoverflow.com/a/46458771/2303865

              – Leo Dabus
              Dec 13 '17 at 3:40













            • @freeman If you would like to preserve the Date with all its fractional seconds I suggest to use a double (time interval since reference date) when saving/receiving your date to the server. And use the default date decoding strategy .deferredToDate when using Codable protocol

              – Leo Dabus
              Dec 13 '17 at 3:47
















            19












            19








            19







            If you want to use the ISO8601DateFormatter() with a date from a Rails 4+ JSON feed (and don't need millis of course), you need to set a few options on the formatter for it to work right otherwise the the date(from: string) function will return nil. Here's what I'm using:



            extension Date {
            init(dateString:String) {
            self = Date.iso8601Formatter.date(from: dateString)!
            }

            static let iso8601Formatter: ISO8601DateFormatter = {
            let formatter = ISO8601DateFormatter()
            formatter.formatOptions = [.withFullDate,
            .withTime,
            .withDashSeparatorInDate,
            .withColonSeparatorInTime]
            return formatter
            }()
            }


            Here's the result of using the options verses not in a playground screenshot:



            enter image description here






            share|improve this answer













            If you want to use the ISO8601DateFormatter() with a date from a Rails 4+ JSON feed (and don't need millis of course), you need to set a few options on the formatter for it to work right otherwise the the date(from: string) function will return nil. Here's what I'm using:



            extension Date {
            init(dateString:String) {
            self = Date.iso8601Formatter.date(from: dateString)!
            }

            static let iso8601Formatter: ISO8601DateFormatter = {
            let formatter = ISO8601DateFormatter()
            formatter.formatOptions = [.withFullDate,
            .withTime,
            .withDashSeparatorInDate,
            .withColonSeparatorInTime]
            return formatter
            }()
            }


            Here's the result of using the options verses not in a playground screenshot:



            enter image description here







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Feb 7 '17 at 23:00









            Matt LongMatt Long

            22.6k46392




            22.6k46392













            • You would need to include in the options also the .withFractionalSeconds but I already tried that and it keeps throwing an error libc++abi.dylib: terminating with uncaught exception of type NSException.

              – Leo Dabus
              Oct 12 '17 at 1:36











            • @MEnnabah It works fine for me in Swift 4. Are you getting an error?

              – Matt Long
              Nov 6 '17 at 16:22











            • @LeoDabus, got the same error as yours, did you solve it?

              – freeman
              Dec 13 '17 at 3:36













            • custom JSONDecoder DateDecodingStrategy stackoverflow.com/a/46458771/2303865

              – Leo Dabus
              Dec 13 '17 at 3:40













            • @freeman If you would like to preserve the Date with all its fractional seconds I suggest to use a double (time interval since reference date) when saving/receiving your date to the server. And use the default date decoding strategy .deferredToDate when using Codable protocol

              – Leo Dabus
              Dec 13 '17 at 3:47





















            • You would need to include in the options also the .withFractionalSeconds but I already tried that and it keeps throwing an error libc++abi.dylib: terminating with uncaught exception of type NSException.

              – Leo Dabus
              Oct 12 '17 at 1:36











            • @MEnnabah It works fine for me in Swift 4. Are you getting an error?

              – Matt Long
              Nov 6 '17 at 16:22











            • @LeoDabus, got the same error as yours, did you solve it?

              – freeman
              Dec 13 '17 at 3:36













            • custom JSONDecoder DateDecodingStrategy stackoverflow.com/a/46458771/2303865

              – Leo Dabus
              Dec 13 '17 at 3:40













            • @freeman If you would like to preserve the Date with all its fractional seconds I suggest to use a double (time interval since reference date) when saving/receiving your date to the server. And use the default date decoding strategy .deferredToDate when using Codable protocol

              – Leo Dabus
              Dec 13 '17 at 3:47



















            You would need to include in the options also the .withFractionalSeconds but I already tried that and it keeps throwing an error libc++abi.dylib: terminating with uncaught exception of type NSException.

            – Leo Dabus
            Oct 12 '17 at 1:36





            You would need to include in the options also the .withFractionalSeconds but I already tried that and it keeps throwing an error libc++abi.dylib: terminating with uncaught exception of type NSException.

            – Leo Dabus
            Oct 12 '17 at 1:36













            @MEnnabah It works fine for me in Swift 4. Are you getting an error?

            – Matt Long
            Nov 6 '17 at 16:22





            @MEnnabah It works fine for me in Swift 4. Are you getting an error?

            – Matt Long
            Nov 6 '17 at 16:22













            @LeoDabus, got the same error as yours, did you solve it?

            – freeman
            Dec 13 '17 at 3:36







            @LeoDabus, got the same error as yours, did you solve it?

            – freeman
            Dec 13 '17 at 3:36















            custom JSONDecoder DateDecodingStrategy stackoverflow.com/a/46458771/2303865

            – Leo Dabus
            Dec 13 '17 at 3:40







            custom JSONDecoder DateDecodingStrategy stackoverflow.com/a/46458771/2303865

            – Leo Dabus
            Dec 13 '17 at 3:40















            @freeman If you would like to preserve the Date with all its fractional seconds I suggest to use a double (time interval since reference date) when saving/receiving your date to the server. And use the default date decoding strategy .deferredToDate when using Codable protocol

            – Leo Dabus
            Dec 13 '17 at 3:47







            @freeman If you would like to preserve the Date with all its fractional seconds I suggest to use a double (time interval since reference date) when saving/receiving your date to the server. And use the default date decoding strategy .deferredToDate when using Codable protocol

            – Leo Dabus
            Dec 13 '17 at 3:47













            4














            To further compliment Andrés Torres Marroquín and Leo Dabus, I have a version that preserves fractional seconds. I can't find it documented anywhere, but Apple truncate fractional seconds to the microsecond (3 digits of precision) on both input and output (even though specified using SSSSSSS, contrary to Unicode tr35-31).



            I should stress that this is probably not necessary for most use cases. Dates online do not typically need millisecond precision, and when they do, it is often better to use a different data format. But sometimes one must interoperate with a pre-existing system in a particular way.



            Xcode 8/9 and Swift 3.0-3.2



            extension Date {
            struct Formatter {
            static let iso8601: DateFormatter = {
            let formatter = DateFormatter()
            formatter.calendar = Calendar(identifier: .iso8601)
            formatter.locale = Locale(identifier: "en_US_POSIX")
            formatter.timeZone = TimeZone(identifier: "UTC")
            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX"
            return formatter
            }()
            }

            var iso8601: String {
            // create base Date format
            var formatted = DateFormatter.iso8601.string(from: self)

            // Apple returns millisecond precision. find the range of the decimal portion
            if let fractionStart = formatted.range(of: "."),
            let fractionEnd = formatted.index(fractionStart.lowerBound, offsetBy: 7, limitedBy: formatted.endIndex) {
            let fractionRange = fractionStart.lowerBound..<fractionEnd
            // replace the decimal range with our own 6 digit fraction output
            let microseconds = self.timeIntervalSince1970 - floor(self.timeIntervalSince1970)
            var microsecondsStr = String(format: "%.06f", microseconds)
            microsecondsStr.remove(at: microsecondsStr.startIndex)
            formatted.replaceSubrange(fractionRange, with: microsecondsStr)
            }
            return formatted
            }
            }

            extension String {
            var dateFromISO8601: Date? {
            guard let parsedDate = Date.Formatter.iso8601.date(from: self) else {
            return nil
            }

            var preliminaryDate = Date(timeIntervalSinceReferenceDate: floor(parsedDate.timeIntervalSinceReferenceDate))

            if let fractionStart = self.range(of: "."),
            let fractionEnd = self.index(fractionStart.lowerBound, offsetBy: 7, limitedBy: self.endIndex) {
            let fractionRange = fractionStart.lowerBound..<fractionEnd
            let fractionStr = self.substring(with: fractionRange)

            if var fraction = Double(fractionStr) {
            fraction = Double(floor(1000000*fraction)/1000000)
            preliminaryDate.addTimeInterval(fraction)
            }
            }
            return preliminaryDate
            }
            }





            share|improve this answer


























            • This is the best answer in my opinion in that it allows one to get to a microsecond level of precision where all the other solutions truncate at milliseconds.

              – Michael A. McCloskey
              Sep 29 '17 at 19:31











            • If you would like to preserve the Date with all its fractional seconds you should use just a double (time interval since reference date) when saving/receiving your date to the server.

              – Leo Dabus
              Dec 13 '17 at 3:45











            • @LeoDabus yes, if you control the whole system and don't need to interoperate. Like I said in the answer, this isn't necessary for most users. But we don't all always have control over the data formatting in web APIs, and as Android and Python (at least) preserve 6 digits of fractional precision, it is sometimes necessary to follow suit.

              – Eli Burke
              Dec 14 '17 at 14:57
















            4














            To further compliment Andrés Torres Marroquín and Leo Dabus, I have a version that preserves fractional seconds. I can't find it documented anywhere, but Apple truncate fractional seconds to the microsecond (3 digits of precision) on both input and output (even though specified using SSSSSSS, contrary to Unicode tr35-31).



            I should stress that this is probably not necessary for most use cases. Dates online do not typically need millisecond precision, and when they do, it is often better to use a different data format. But sometimes one must interoperate with a pre-existing system in a particular way.



            Xcode 8/9 and Swift 3.0-3.2



            extension Date {
            struct Formatter {
            static let iso8601: DateFormatter = {
            let formatter = DateFormatter()
            formatter.calendar = Calendar(identifier: .iso8601)
            formatter.locale = Locale(identifier: "en_US_POSIX")
            formatter.timeZone = TimeZone(identifier: "UTC")
            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX"
            return formatter
            }()
            }

            var iso8601: String {
            // create base Date format
            var formatted = DateFormatter.iso8601.string(from: self)

            // Apple returns millisecond precision. find the range of the decimal portion
            if let fractionStart = formatted.range(of: "."),
            let fractionEnd = formatted.index(fractionStart.lowerBound, offsetBy: 7, limitedBy: formatted.endIndex) {
            let fractionRange = fractionStart.lowerBound..<fractionEnd
            // replace the decimal range with our own 6 digit fraction output
            let microseconds = self.timeIntervalSince1970 - floor(self.timeIntervalSince1970)
            var microsecondsStr = String(format: "%.06f", microseconds)
            microsecondsStr.remove(at: microsecondsStr.startIndex)
            formatted.replaceSubrange(fractionRange, with: microsecondsStr)
            }
            return formatted
            }
            }

            extension String {
            var dateFromISO8601: Date? {
            guard let parsedDate = Date.Formatter.iso8601.date(from: self) else {
            return nil
            }

            var preliminaryDate = Date(timeIntervalSinceReferenceDate: floor(parsedDate.timeIntervalSinceReferenceDate))

            if let fractionStart = self.range(of: "."),
            let fractionEnd = self.index(fractionStart.lowerBound, offsetBy: 7, limitedBy: self.endIndex) {
            let fractionRange = fractionStart.lowerBound..<fractionEnd
            let fractionStr = self.substring(with: fractionRange)

            if var fraction = Double(fractionStr) {
            fraction = Double(floor(1000000*fraction)/1000000)
            preliminaryDate.addTimeInterval(fraction)
            }
            }
            return preliminaryDate
            }
            }





            share|improve this answer


























            • This is the best answer in my opinion in that it allows one to get to a microsecond level of precision where all the other solutions truncate at milliseconds.

              – Michael A. McCloskey
              Sep 29 '17 at 19:31











            • If you would like to preserve the Date with all its fractional seconds you should use just a double (time interval since reference date) when saving/receiving your date to the server.

              – Leo Dabus
              Dec 13 '17 at 3:45











            • @LeoDabus yes, if you control the whole system and don't need to interoperate. Like I said in the answer, this isn't necessary for most users. But we don't all always have control over the data formatting in web APIs, and as Android and Python (at least) preserve 6 digits of fractional precision, it is sometimes necessary to follow suit.

              – Eli Burke
              Dec 14 '17 at 14:57














            4












            4








            4







            To further compliment Andrés Torres Marroquín and Leo Dabus, I have a version that preserves fractional seconds. I can't find it documented anywhere, but Apple truncate fractional seconds to the microsecond (3 digits of precision) on both input and output (even though specified using SSSSSSS, contrary to Unicode tr35-31).



            I should stress that this is probably not necessary for most use cases. Dates online do not typically need millisecond precision, and when they do, it is often better to use a different data format. But sometimes one must interoperate with a pre-existing system in a particular way.



            Xcode 8/9 and Swift 3.0-3.2



            extension Date {
            struct Formatter {
            static let iso8601: DateFormatter = {
            let formatter = DateFormatter()
            formatter.calendar = Calendar(identifier: .iso8601)
            formatter.locale = Locale(identifier: "en_US_POSIX")
            formatter.timeZone = TimeZone(identifier: "UTC")
            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX"
            return formatter
            }()
            }

            var iso8601: String {
            // create base Date format
            var formatted = DateFormatter.iso8601.string(from: self)

            // Apple returns millisecond precision. find the range of the decimal portion
            if let fractionStart = formatted.range(of: "."),
            let fractionEnd = formatted.index(fractionStart.lowerBound, offsetBy: 7, limitedBy: formatted.endIndex) {
            let fractionRange = fractionStart.lowerBound..<fractionEnd
            // replace the decimal range with our own 6 digit fraction output
            let microseconds = self.timeIntervalSince1970 - floor(self.timeIntervalSince1970)
            var microsecondsStr = String(format: "%.06f", microseconds)
            microsecondsStr.remove(at: microsecondsStr.startIndex)
            formatted.replaceSubrange(fractionRange, with: microsecondsStr)
            }
            return formatted
            }
            }

            extension String {
            var dateFromISO8601: Date? {
            guard let parsedDate = Date.Formatter.iso8601.date(from: self) else {
            return nil
            }

            var preliminaryDate = Date(timeIntervalSinceReferenceDate: floor(parsedDate.timeIntervalSinceReferenceDate))

            if let fractionStart = self.range(of: "."),
            let fractionEnd = self.index(fractionStart.lowerBound, offsetBy: 7, limitedBy: self.endIndex) {
            let fractionRange = fractionStart.lowerBound..<fractionEnd
            let fractionStr = self.substring(with: fractionRange)

            if var fraction = Double(fractionStr) {
            fraction = Double(floor(1000000*fraction)/1000000)
            preliminaryDate.addTimeInterval(fraction)
            }
            }
            return preliminaryDate
            }
            }





            share|improve this answer















            To further compliment Andrés Torres Marroquín and Leo Dabus, I have a version that preserves fractional seconds. I can't find it documented anywhere, but Apple truncate fractional seconds to the microsecond (3 digits of precision) on both input and output (even though specified using SSSSSSS, contrary to Unicode tr35-31).



            I should stress that this is probably not necessary for most use cases. Dates online do not typically need millisecond precision, and when they do, it is often better to use a different data format. But sometimes one must interoperate with a pre-existing system in a particular way.



            Xcode 8/9 and Swift 3.0-3.2



            extension Date {
            struct Formatter {
            static let iso8601: DateFormatter = {
            let formatter = DateFormatter()
            formatter.calendar = Calendar(identifier: .iso8601)
            formatter.locale = Locale(identifier: "en_US_POSIX")
            formatter.timeZone = TimeZone(identifier: "UTC")
            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX"
            return formatter
            }()
            }

            var iso8601: String {
            // create base Date format
            var formatted = DateFormatter.iso8601.string(from: self)

            // Apple returns millisecond precision. find the range of the decimal portion
            if let fractionStart = formatted.range(of: "."),
            let fractionEnd = formatted.index(fractionStart.lowerBound, offsetBy: 7, limitedBy: formatted.endIndex) {
            let fractionRange = fractionStart.lowerBound..<fractionEnd
            // replace the decimal range with our own 6 digit fraction output
            let microseconds = self.timeIntervalSince1970 - floor(self.timeIntervalSince1970)
            var microsecondsStr = String(format: "%.06f", microseconds)
            microsecondsStr.remove(at: microsecondsStr.startIndex)
            formatted.replaceSubrange(fractionRange, with: microsecondsStr)
            }
            return formatted
            }
            }

            extension String {
            var dateFromISO8601: Date? {
            guard let parsedDate = Date.Formatter.iso8601.date(from: self) else {
            return nil
            }

            var preliminaryDate = Date(timeIntervalSinceReferenceDate: floor(parsedDate.timeIntervalSinceReferenceDate))

            if let fractionStart = self.range(of: "."),
            let fractionEnd = self.index(fractionStart.lowerBound, offsetBy: 7, limitedBy: self.endIndex) {
            let fractionRange = fractionStart.lowerBound..<fractionEnd
            let fractionStr = self.substring(with: fractionRange)

            if var fraction = Double(fractionStr) {
            fraction = Double(floor(1000000*fraction)/1000000)
            preliminaryDate.addTimeInterval(fraction)
            }
            }
            return preliminaryDate
            }
            }






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jul 12 '18 at 15:18

























            answered Apr 14 '17 at 13:30









            Eli BurkeEli Burke

            2,0021918




            2,0021918













            • This is the best answer in my opinion in that it allows one to get to a microsecond level of precision where all the other solutions truncate at milliseconds.

              – Michael A. McCloskey
              Sep 29 '17 at 19:31











            • If you would like to preserve the Date with all its fractional seconds you should use just a double (time interval since reference date) when saving/receiving your date to the server.

              – Leo Dabus
              Dec 13 '17 at 3:45











            • @LeoDabus yes, if you control the whole system and don't need to interoperate. Like I said in the answer, this isn't necessary for most users. But we don't all always have control over the data formatting in web APIs, and as Android and Python (at least) preserve 6 digits of fractional precision, it is sometimes necessary to follow suit.

              – Eli Burke
              Dec 14 '17 at 14:57



















            • This is the best answer in my opinion in that it allows one to get to a microsecond level of precision where all the other solutions truncate at milliseconds.

              – Michael A. McCloskey
              Sep 29 '17 at 19:31











            • If you would like to preserve the Date with all its fractional seconds you should use just a double (time interval since reference date) when saving/receiving your date to the server.

              – Leo Dabus
              Dec 13 '17 at 3:45











            • @LeoDabus yes, if you control the whole system and don't need to interoperate. Like I said in the answer, this isn't necessary for most users. But we don't all always have control over the data formatting in web APIs, and as Android and Python (at least) preserve 6 digits of fractional precision, it is sometimes necessary to follow suit.

              – Eli Burke
              Dec 14 '17 at 14:57

















            This is the best answer in my opinion in that it allows one to get to a microsecond level of precision where all the other solutions truncate at milliseconds.

            – Michael A. McCloskey
            Sep 29 '17 at 19:31





            This is the best answer in my opinion in that it allows one to get to a microsecond level of precision where all the other solutions truncate at milliseconds.

            – Michael A. McCloskey
            Sep 29 '17 at 19:31













            If you would like to preserve the Date with all its fractional seconds you should use just a double (time interval since reference date) when saving/receiving your date to the server.

            – Leo Dabus
            Dec 13 '17 at 3:45





            If you would like to preserve the Date with all its fractional seconds you should use just a double (time interval since reference date) when saving/receiving your date to the server.

            – Leo Dabus
            Dec 13 '17 at 3:45













            @LeoDabus yes, if you control the whole system and don't need to interoperate. Like I said in the answer, this isn't necessary for most users. But we don't all always have control over the data formatting in web APIs, and as Android and Python (at least) preserve 6 digits of fractional precision, it is sometimes necessary to follow suit.

            – Eli Burke
            Dec 14 '17 at 14:57





            @LeoDabus yes, if you control the whole system and don't need to interoperate. Like I said in the answer, this isn't necessary for most users. But we don't all always have control over the data formatting in web APIs, and as Android and Python (at least) preserve 6 digits of fractional precision, it is sometimes necessary to follow suit.

            – Eli Burke
            Dec 14 '17 at 14:57











            3














            In my case I have to convert the DynamoDB - lastUpdated column (Unix Timestamp) to Normal Time.



            The initial value of lastUpdated was : 1460650607601 - converted down to 2016-04-14 16:16:47 +0000 via :



               if let lastUpdated : String = userObject.lastUpdated {

            let epocTime = NSTimeInterval(lastUpdated)! / 1000 // convert it from milliseconds dividing it by 1000

            let unixTimestamp = NSDate(timeIntervalSince1970: epocTime) //convert unix timestamp to Date
            let dateFormatter = NSDateFormatter()
            dateFormatter.timeZone = NSTimeZone()
            dateFormatter.locale = NSLocale.currentLocale() // NSLocale(localeIdentifier: "en_US_POSIX")
            dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
            dateFormatter.dateFromString(String(unixTimestamp))

            let updatedTimeStamp = unixTimestamp
            print(updatedTimeStamp)

            }





            share|improve this answer




























              3














              In my case I have to convert the DynamoDB - lastUpdated column (Unix Timestamp) to Normal Time.



              The initial value of lastUpdated was : 1460650607601 - converted down to 2016-04-14 16:16:47 +0000 via :



                 if let lastUpdated : String = userObject.lastUpdated {

              let epocTime = NSTimeInterval(lastUpdated)! / 1000 // convert it from milliseconds dividing it by 1000

              let unixTimestamp = NSDate(timeIntervalSince1970: epocTime) //convert unix timestamp to Date
              let dateFormatter = NSDateFormatter()
              dateFormatter.timeZone = NSTimeZone()
              dateFormatter.locale = NSLocale.currentLocale() // NSLocale(localeIdentifier: "en_US_POSIX")
              dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
              dateFormatter.dateFromString(String(unixTimestamp))

              let updatedTimeStamp = unixTimestamp
              print(updatedTimeStamp)

              }





              share|improve this answer


























                3












                3








                3







                In my case I have to convert the DynamoDB - lastUpdated column (Unix Timestamp) to Normal Time.



                The initial value of lastUpdated was : 1460650607601 - converted down to 2016-04-14 16:16:47 +0000 via :



                   if let lastUpdated : String = userObject.lastUpdated {

                let epocTime = NSTimeInterval(lastUpdated)! / 1000 // convert it from milliseconds dividing it by 1000

                let unixTimestamp = NSDate(timeIntervalSince1970: epocTime) //convert unix timestamp to Date
                let dateFormatter = NSDateFormatter()
                dateFormatter.timeZone = NSTimeZone()
                dateFormatter.locale = NSLocale.currentLocale() // NSLocale(localeIdentifier: "en_US_POSIX")
                dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
                dateFormatter.dateFromString(String(unixTimestamp))

                let updatedTimeStamp = unixTimestamp
                print(updatedTimeStamp)

                }





                share|improve this answer













                In my case I have to convert the DynamoDB - lastUpdated column (Unix Timestamp) to Normal Time.



                The initial value of lastUpdated was : 1460650607601 - converted down to 2016-04-14 16:16:47 +0000 via :



                   if let lastUpdated : String = userObject.lastUpdated {

                let epocTime = NSTimeInterval(lastUpdated)! / 1000 // convert it from milliseconds dividing it by 1000

                let unixTimestamp = NSDate(timeIntervalSince1970: epocTime) //convert unix timestamp to Date
                let dateFormatter = NSDateFormatter()
                dateFormatter.timeZone = NSTimeZone()
                dateFormatter.locale = NSLocale.currentLocale() // NSLocale(localeIdentifier: "en_US_POSIX")
                dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
                dateFormatter.dateFromString(String(unixTimestamp))

                let updatedTimeStamp = unixTimestamp
                print(updatedTimeStamp)

                }






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Apr 15 '16 at 11:09









                iooplioopl

                1,3721416




                1,3721416























                    3














                    In the future the format might need to be changed which could be a small head ache having date.dateFromISO8601 calls everywhere in an app. Use a class and protocol to wrap the implementation, changing the date time format call in one place will be simpler. Use RFC3339 if possible, its a more complete representation. DateFormatProtocol and DateFormat is great for dependency injection.



                    class AppDelegate: UIResponder, UIApplicationDelegate {

                    internal static let rfc3339DateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
                    internal static let localeEnUsPosix = "en_US_POSIX"
                    }

                    import Foundation

                    protocol DateFormatProtocol {

                    func format(date: NSDate) -> String
                    func parse(date: String) -> NSDate?

                    }


                    import Foundation

                    class DateFormat: DateFormatProtocol {

                    func format(date: NSDate) -> String {
                    return date.rfc3339
                    }

                    func parse(date: String) -> NSDate? {
                    return date.rfc3339
                    }

                    }


                    extension NSDate {

                    struct Formatter {
                    static let rfc3339: NSDateFormatter = {
                    let formatter = NSDateFormatter()
                    formatter.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601)
                    formatter.locale = NSLocale(localeIdentifier: AppDelegate.localeEnUsPosix)
                    formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
                    formatter.dateFormat = rfc3339DateFormat
                    return formatter
                    }()
                    }

                    var rfc3339: String { return Formatter.rfc3339.stringFromDate(self) }
                    }

                    extension String {
                    var rfc3339: NSDate? {
                    return NSDate.Formatter.rfc3339.dateFromString(self)
                    }
                    }



                    class DependencyService: DependencyServiceProtocol {

                    private var dateFormat: DateFormatProtocol?

                    func setDateFormat(dateFormat: DateFormatProtocol) {
                    self.dateFormat = dateFormat
                    }

                    func getDateFormat() -> DateFormatProtocol {
                    if let dateFormatObject = dateFormat {

                    return dateFormatObject
                    } else {
                    let dateFormatObject = DateFormat()
                    dateFormat = dateFormatObject

                    return dateFormatObject
                    }
                    }

                    }





                    share|improve this answer






























                      3














                      In the future the format might need to be changed which could be a small head ache having date.dateFromISO8601 calls everywhere in an app. Use a class and protocol to wrap the implementation, changing the date time format call in one place will be simpler. Use RFC3339 if possible, its a more complete representation. DateFormatProtocol and DateFormat is great for dependency injection.



                      class AppDelegate: UIResponder, UIApplicationDelegate {

                      internal static let rfc3339DateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
                      internal static let localeEnUsPosix = "en_US_POSIX"
                      }

                      import Foundation

                      protocol DateFormatProtocol {

                      func format(date: NSDate) -> String
                      func parse(date: String) -> NSDate?

                      }


                      import Foundation

                      class DateFormat: DateFormatProtocol {

                      func format(date: NSDate) -> String {
                      return date.rfc3339
                      }

                      func parse(date: String) -> NSDate? {
                      return date.rfc3339
                      }

                      }


                      extension NSDate {

                      struct Formatter {
                      static let rfc3339: NSDateFormatter = {
                      let formatter = NSDateFormatter()
                      formatter.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601)
                      formatter.locale = NSLocale(localeIdentifier: AppDelegate.localeEnUsPosix)
                      formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
                      formatter.dateFormat = rfc3339DateFormat
                      return formatter
                      }()
                      }

                      var rfc3339: String { return Formatter.rfc3339.stringFromDate(self) }
                      }

                      extension String {
                      var rfc3339: NSDate? {
                      return NSDate.Formatter.rfc3339.dateFromString(self)
                      }
                      }



                      class DependencyService: DependencyServiceProtocol {

                      private var dateFormat: DateFormatProtocol?

                      func setDateFormat(dateFormat: DateFormatProtocol) {
                      self.dateFormat = dateFormat
                      }

                      func getDateFormat() -> DateFormatProtocol {
                      if let dateFormatObject = dateFormat {

                      return dateFormatObject
                      } else {
                      let dateFormatObject = DateFormat()
                      dateFormat = dateFormatObject

                      return dateFormatObject
                      }
                      }

                      }





                      share|improve this answer




























                        3












                        3








                        3







                        In the future the format might need to be changed which could be a small head ache having date.dateFromISO8601 calls everywhere in an app. Use a class and protocol to wrap the implementation, changing the date time format call in one place will be simpler. Use RFC3339 if possible, its a more complete representation. DateFormatProtocol and DateFormat is great for dependency injection.



                        class AppDelegate: UIResponder, UIApplicationDelegate {

                        internal static let rfc3339DateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
                        internal static let localeEnUsPosix = "en_US_POSIX"
                        }

                        import Foundation

                        protocol DateFormatProtocol {

                        func format(date: NSDate) -> String
                        func parse(date: String) -> NSDate?

                        }


                        import Foundation

                        class DateFormat: DateFormatProtocol {

                        func format(date: NSDate) -> String {
                        return date.rfc3339
                        }

                        func parse(date: String) -> NSDate? {
                        return date.rfc3339
                        }

                        }


                        extension NSDate {

                        struct Formatter {
                        static let rfc3339: NSDateFormatter = {
                        let formatter = NSDateFormatter()
                        formatter.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601)
                        formatter.locale = NSLocale(localeIdentifier: AppDelegate.localeEnUsPosix)
                        formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
                        formatter.dateFormat = rfc3339DateFormat
                        return formatter
                        }()
                        }

                        var rfc3339: String { return Formatter.rfc3339.stringFromDate(self) }
                        }

                        extension String {
                        var rfc3339: NSDate? {
                        return NSDate.Formatter.rfc3339.dateFromString(self)
                        }
                        }



                        class DependencyService: DependencyServiceProtocol {

                        private var dateFormat: DateFormatProtocol?

                        func setDateFormat(dateFormat: DateFormatProtocol) {
                        self.dateFormat = dateFormat
                        }

                        func getDateFormat() -> DateFormatProtocol {
                        if let dateFormatObject = dateFormat {

                        return dateFormatObject
                        } else {
                        let dateFormatObject = DateFormat()
                        dateFormat = dateFormatObject

                        return dateFormatObject
                        }
                        }

                        }





                        share|improve this answer















                        In the future the format might need to be changed which could be a small head ache having date.dateFromISO8601 calls everywhere in an app. Use a class and protocol to wrap the implementation, changing the date time format call in one place will be simpler. Use RFC3339 if possible, its a more complete representation. DateFormatProtocol and DateFormat is great for dependency injection.



                        class AppDelegate: UIResponder, UIApplicationDelegate {

                        internal static let rfc3339DateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
                        internal static let localeEnUsPosix = "en_US_POSIX"
                        }

                        import Foundation

                        protocol DateFormatProtocol {

                        func format(date: NSDate) -> String
                        func parse(date: String) -> NSDate?

                        }


                        import Foundation

                        class DateFormat: DateFormatProtocol {

                        func format(date: NSDate) -> String {
                        return date.rfc3339
                        }

                        func parse(date: String) -> NSDate? {
                        return date.rfc3339
                        }

                        }


                        extension NSDate {

                        struct Formatter {
                        static let rfc3339: NSDateFormatter = {
                        let formatter = NSDateFormatter()
                        formatter.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601)
                        formatter.locale = NSLocale(localeIdentifier: AppDelegate.localeEnUsPosix)
                        formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
                        formatter.dateFormat = rfc3339DateFormat
                        return formatter
                        }()
                        }

                        var rfc3339: String { return Formatter.rfc3339.stringFromDate(self) }
                        }

                        extension String {
                        var rfc3339: NSDate? {
                        return NSDate.Formatter.rfc3339.dateFromString(self)
                        }
                        }



                        class DependencyService: DependencyServiceProtocol {

                        private var dateFormat: DateFormatProtocol?

                        func setDateFormat(dateFormat: DateFormatProtocol) {
                        self.dateFormat = dateFormat
                        }

                        func getDateFormat() -> DateFormatProtocol {
                        if let dateFormatObject = dateFormat {

                        return dateFormatObject
                        } else {
                        let dateFormatObject = DateFormat()
                        dateFormat = dateFormatObject

                        return dateFormatObject
                        }
                        }

                        }






                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited Dec 5 '16 at 3:57

























                        answered Dec 5 '16 at 3:13









                        Gary DaviesGary Davies

                        56289




                        56289























                            3














                            There is a new ISO8601DateFormatter class that let's you create a string with just one line. For backwards compatibility I used an old C-library. I hope this is useful for someone.



                            Swift 3.0



                            extension Date {
                            var iso8601: String {
                            if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
                            return ISO8601DateFormatter.string(from: self, timeZone: TimeZone.current, formatOptions: .withInternetDateTime)
                            } else {
                            var buffer = [CChar](repeating: 0, count: 25)
                            var time = time_t(self.timeIntervalSince1970)
                            strftime_l(&buffer, buffer.count, "%FT%T%z", localtime(&time), nil)
                            return String(cString: buffer)
                            }
                            }
                            }





                            share|improve this answer




























                              3














                              There is a new ISO8601DateFormatter class that let's you create a string with just one line. For backwards compatibility I used an old C-library. I hope this is useful for someone.



                              Swift 3.0



                              extension Date {
                              var iso8601: String {
                              if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
                              return ISO8601DateFormatter.string(from: self, timeZone: TimeZone.current, formatOptions: .withInternetDateTime)
                              } else {
                              var buffer = [CChar](repeating: 0, count: 25)
                              var time = time_t(self.timeIntervalSince1970)
                              strftime_l(&buffer, buffer.count, "%FT%T%z", localtime(&time), nil)
                              return String(cString: buffer)
                              }
                              }
                              }





                              share|improve this answer


























                                3












                                3








                                3







                                There is a new ISO8601DateFormatter class that let's you create a string with just one line. For backwards compatibility I used an old C-library. I hope this is useful for someone.



                                Swift 3.0



                                extension Date {
                                var iso8601: String {
                                if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
                                return ISO8601DateFormatter.string(from: self, timeZone: TimeZone.current, formatOptions: .withInternetDateTime)
                                } else {
                                var buffer = [CChar](repeating: 0, count: 25)
                                var time = time_t(self.timeIntervalSince1970)
                                strftime_l(&buffer, buffer.count, "%FT%T%z", localtime(&time), nil)
                                return String(cString: buffer)
                                }
                                }
                                }





                                share|improve this answer













                                There is a new ISO8601DateFormatter class that let's you create a string with just one line. For backwards compatibility I used an old C-library. I hope this is useful for someone.



                                Swift 3.0



                                extension Date {
                                var iso8601: String {
                                if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
                                return ISO8601DateFormatter.string(from: self, timeZone: TimeZone.current, formatOptions: .withInternetDateTime)
                                } else {
                                var buffer = [CChar](repeating: 0, count: 25)
                                var time = time_t(self.timeIntervalSince1970)
                                strftime_l(&buffer, buffer.count, "%FT%T%z", localtime(&time), nil)
                                return String(cString: buffer)
                                }
                                }
                                }






                                share|improve this answer












                                share|improve this answer



                                share|improve this answer










                                answered Jun 28 '17 at 15:35









                                Thomas SzaboThomas Szabo

                                884




                                884























                                    2














                                    Uses ISO8601DateFormatter on iOS10 or newer.



                                    Uses DateFormatter on iOS9 or older.



                                    Swift 4



                                    protocol DateFormatterProtocol {
                                    func string(from date: Date) -> String
                                    func date(from string: String) -> Date?
                                    }

                                    extension DateFormatter: DateFormatterProtocol {}

                                    @available(iOS 10.0, *)
                                    extension ISO8601DateFormatter: DateFormatterProtocol {}

                                    struct DateFormatterShared {
                                    static let iso8601: DateFormatterProtocol = {
                                    if #available(iOS 10, *) {
                                    return ISO8601DateFormatter()
                                    } else {
                                    // iOS 9
                                    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
                                    }
                                    }()
                                    }





                                    share|improve this answer




























                                      2














                                      Uses ISO8601DateFormatter on iOS10 or newer.



                                      Uses DateFormatter on iOS9 or older.



                                      Swift 4



                                      protocol DateFormatterProtocol {
                                      func string(from date: Date) -> String
                                      func date(from string: String) -> Date?
                                      }

                                      extension DateFormatter: DateFormatterProtocol {}

                                      @available(iOS 10.0, *)
                                      extension ISO8601DateFormatter: DateFormatterProtocol {}

                                      struct DateFormatterShared {
                                      static let iso8601: DateFormatterProtocol = {
                                      if #available(iOS 10, *) {
                                      return ISO8601DateFormatter()
                                      } else {
                                      // iOS 9
                                      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
                                      }
                                      }()
                                      }





                                      share|improve this answer


























                                        2












                                        2








                                        2







                                        Uses ISO8601DateFormatter on iOS10 or newer.



                                        Uses DateFormatter on iOS9 or older.



                                        Swift 4



                                        protocol DateFormatterProtocol {
                                        func string(from date: Date) -> String
                                        func date(from string: String) -> Date?
                                        }

                                        extension DateFormatter: DateFormatterProtocol {}

                                        @available(iOS 10.0, *)
                                        extension ISO8601DateFormatter: DateFormatterProtocol {}

                                        struct DateFormatterShared {
                                        static let iso8601: DateFormatterProtocol = {
                                        if #available(iOS 10, *) {
                                        return ISO8601DateFormatter()
                                        } else {
                                        // iOS 9
                                        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
                                        }
                                        }()
                                        }





                                        share|improve this answer













                                        Uses ISO8601DateFormatter on iOS10 or newer.



                                        Uses DateFormatter on iOS9 or older.



                                        Swift 4



                                        protocol DateFormatterProtocol {
                                        func string(from date: Date) -> String
                                        func date(from string: String) -> Date?
                                        }

                                        extension DateFormatter: DateFormatterProtocol {}

                                        @available(iOS 10.0, *)
                                        extension ISO8601DateFormatter: DateFormatterProtocol {}

                                        struct DateFormatterShared {
                                        static let iso8601: DateFormatterProtocol = {
                                        if #available(iOS 10, *) {
                                        return ISO8601DateFormatter()
                                        } else {
                                        // iOS 9
                                        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
                                        }
                                        }()
                                        }






                                        share|improve this answer












                                        share|improve this answer



                                        share|improve this answer










                                        answered Mar 8 '18 at 13:14









                                        neoneyeneoneye

                                        31.1k19132124




                                        31.1k19132124























                                            0














                                            To complement the version of Leo Dabus, I added support for projects written Swift and Objective-C, also added support for the optional milliseconds, probably isn't the best but you would get the point:



                                            Xcode 8 and Swift 3



                                            extension Date {
                                            struct Formatter {
                                            static let iso8601: 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
                                            }()
                                            }

                                            var iso8601: String {
                                            return Formatter.iso8601.string(from: self)
                                            }
                                            }


                                            extension String {
                                            var dateFromISO8601: Date? {
                                            var data = self
                                            if self.range(of: ".") == nil {
                                            // Case where the string doesn't contain the optional milliseconds
                                            data = data.replacingOccurrences(of: "Z", with: ".000000Z")
                                            }
                                            return Date.Formatter.iso8601.date(from: data)
                                            }
                                            }


                                            extension NSString {
                                            var dateFromISO8601: Date? {
                                            return (self as String).dateFromISO8601
                                            }
                                            }





                                            share|improve this answer




























                                              0














                                              To complement the version of Leo Dabus, I added support for projects written Swift and Objective-C, also added support for the optional milliseconds, probably isn't the best but you would get the point:



                                              Xcode 8 and Swift 3



                                              extension Date {
                                              struct Formatter {
                                              static let iso8601: 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
                                              }()
                                              }

                                              var iso8601: String {
                                              return Formatter.iso8601.string(from: self)
                                              }
                                              }


                                              extension String {
                                              var dateFromISO8601: Date? {
                                              var data = self
                                              if self.range(of: ".") == nil {
                                              // Case where the string doesn't contain the optional milliseconds
                                              data = data.replacingOccurrences(of: "Z", with: ".000000Z")
                                              }
                                              return Date.Formatter.iso8601.date(from: data)
                                              }
                                              }


                                              extension NSString {
                                              var dateFromISO8601: Date? {
                                              return (self as String).dateFromISO8601
                                              }
                                              }





                                              share|improve this answer


























                                                0












                                                0








                                                0







                                                To complement the version of Leo Dabus, I added support for projects written Swift and Objective-C, also added support for the optional milliseconds, probably isn't the best but you would get the point:



                                                Xcode 8 and Swift 3



                                                extension Date {
                                                struct Formatter {
                                                static let iso8601: 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
                                                }()
                                                }

                                                var iso8601: String {
                                                return Formatter.iso8601.string(from: self)
                                                }
                                                }


                                                extension String {
                                                var dateFromISO8601: Date? {
                                                var data = self
                                                if self.range(of: ".") == nil {
                                                // Case where the string doesn't contain the optional milliseconds
                                                data = data.replacingOccurrences(of: "Z", with: ".000000Z")
                                                }
                                                return Date.Formatter.iso8601.date(from: data)
                                                }
                                                }


                                                extension NSString {
                                                var dateFromISO8601: Date? {
                                                return (self as String).dateFromISO8601
                                                }
                                                }





                                                share|improve this answer













                                                To complement the version of Leo Dabus, I added support for projects written Swift and Objective-C, also added support for the optional milliseconds, probably isn't the best but you would get the point:



                                                Xcode 8 and Swift 3



                                                extension Date {
                                                struct Formatter {
                                                static let iso8601: 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
                                                }()
                                                }

                                                var iso8601: String {
                                                return Formatter.iso8601.string(from: self)
                                                }
                                                }


                                                extension String {
                                                var dateFromISO8601: Date? {
                                                var data = self
                                                if self.range(of: ".") == nil {
                                                // Case where the string doesn't contain the optional milliseconds
                                                data = data.replacingOccurrences(of: "Z", with: ".000000Z")
                                                }
                                                return Date.Formatter.iso8601.date(from: data)
                                                }
                                                }


                                                extension NSString {
                                                var dateFromISO8601: Date? {
                                                return (self as String).dateFromISO8601
                                                }
                                                }






                                                share|improve this answer












                                                share|improve this answer



                                                share|improve this answer










                                                answered Nov 3 '16 at 16:22









                                                Andrés Torres MarroquínAndrés Torres Marroquín

                                                1,5561212




                                                1,5561212























                                                    0














                                                    Without some manual String masks or TimeFormatters



                                                    import Foundation

                                                    struct DateISO: Codable {
                                                    var date: Date
                                                    }

                                                    extension Date{
                                                    var isoString: String {
                                                    let encoder = JSONEncoder()
                                                    encoder.dateEncodingStrategy = .iso8601
                                                    guard let data = try? encoder.encode(DateISO(date: self)),
                                                    let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: String]
                                                    else { return "" }
                                                    return json?.first?.value ?? ""
                                                    }
                                                    }

                                                    let dateString = Date().isoString





                                                    share|improve this answer
























                                                    • Note that this will create a JSONEncoder object every time you call this property. FYI options: .allowFragments is pointless and can just be omitted. Btw your approach would be much easier if you encode your date as a single element collection.

                                                      – Leo Dabus
                                                      Feb 6 at 11:17











                                                    • extension JSONEncoder { static let iso8601: JSONEncoder = { let iso8601 = JSONEncoder() iso8601.dateEncodingStrategy = .iso8601 return iso8601 }() } extension Date { var isoString: String { return (try! JSONSerialization.jsonObject(with: JSONEncoder.iso8601.encode([self])) as! [String]).first! } } and don't worry about forcing unwrap, it will never fail in this case.

                                                      – Leo Dabus
                                                      Feb 6 at 11:18













                                                    • Another option when using the array approach is to drop the first and last 2 bytes of the encoded data and convert the subdata to string. extension Date { var isoString: String { return try! String(data: JSONEncoder.iso8601.encode([self])[2..<22], encoding: .utf8)! } }

                                                      – Leo Dabus
                                                      Feb 6 at 11:49


















                                                    0














                                                    Without some manual String masks or TimeFormatters



                                                    import Foundation

                                                    struct DateISO: Codable {
                                                    var date: Date
                                                    }

                                                    extension Date{
                                                    var isoString: String {
                                                    let encoder = JSONEncoder()
                                                    encoder.dateEncodingStrategy = .iso8601
                                                    guard let data = try? encoder.encode(DateISO(date: self)),
                                                    let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: String]
                                                    else { return "" }
                                                    return json?.first?.value ?? ""
                                                    }
                                                    }

                                                    let dateString = Date().isoString





                                                    share|improve this answer
























                                                    • Note that this will create a JSONEncoder object every time you call this property. FYI options: .allowFragments is pointless and can just be omitted. Btw your approach would be much easier if you encode your date as a single element collection.

                                                      – Leo Dabus
                                                      Feb 6 at 11:17











                                                    • extension JSONEncoder { static let iso8601: JSONEncoder = { let iso8601 = JSONEncoder() iso8601.dateEncodingStrategy = .iso8601 return iso8601 }() } extension Date { var isoString: String { return (try! JSONSerialization.jsonObject(with: JSONEncoder.iso8601.encode([self])) as! [String]).first! } } and don't worry about forcing unwrap, it will never fail in this case.

                                                      – Leo Dabus
                                                      Feb 6 at 11:18













                                                    • Another option when using the array approach is to drop the first and last 2 bytes of the encoded data and convert the subdata to string. extension Date { var isoString: String { return try! String(data: JSONEncoder.iso8601.encode([self])[2..<22], encoding: .utf8)! } }

                                                      – Leo Dabus
                                                      Feb 6 at 11:49
















                                                    0












                                                    0








                                                    0







                                                    Without some manual String masks or TimeFormatters



                                                    import Foundation

                                                    struct DateISO: Codable {
                                                    var date: Date
                                                    }

                                                    extension Date{
                                                    var isoString: String {
                                                    let encoder = JSONEncoder()
                                                    encoder.dateEncodingStrategy = .iso8601
                                                    guard let data = try? encoder.encode(DateISO(date: self)),
                                                    let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: String]
                                                    else { return "" }
                                                    return json?.first?.value ?? ""
                                                    }
                                                    }

                                                    let dateString = Date().isoString





                                                    share|improve this answer













                                                    Without some manual String masks or TimeFormatters



                                                    import Foundation

                                                    struct DateISO: Codable {
                                                    var date: Date
                                                    }

                                                    extension Date{
                                                    var isoString: String {
                                                    let encoder = JSONEncoder()
                                                    encoder.dateEncodingStrategy = .iso8601
                                                    guard let data = try? encoder.encode(DateISO(date: self)),
                                                    let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: String]
                                                    else { return "" }
                                                    return json?.first?.value ?? ""
                                                    }
                                                    }

                                                    let dateString = Date().isoString






                                                    share|improve this answer












                                                    share|improve this answer



                                                    share|improve this answer










                                                    answered Dec 4 '18 at 5:33









                                                    Dmitrii ZDmitrii Z

                                                    8913




                                                    8913













                                                    • Note that this will create a JSONEncoder object every time you call this property. FYI options: .allowFragments is pointless and can just be omitted. Btw your approach would be much easier if you encode your date as a single element collection.

                                                      – Leo Dabus
                                                      Feb 6 at 11:17











                                                    • extension JSONEncoder { static let iso8601: JSONEncoder = { let iso8601 = JSONEncoder() iso8601.dateEncodingStrategy = .iso8601 return iso8601 }() } extension Date { var isoString: String { return (try! JSONSerialization.jsonObject(with: JSONEncoder.iso8601.encode([self])) as! [String]).first! } } and don't worry about forcing unwrap, it will never fail in this case.

                                                      – Leo Dabus
                                                      Feb 6 at 11:18













                                                    • Another option when using the array approach is to drop the first and last 2 bytes of the encoded data and convert the subdata to string. extension Date { var isoString: String { return try! String(data: JSONEncoder.iso8601.encode([self])[2..<22], encoding: .utf8)! } }

                                                      – Leo Dabus
                                                      Feb 6 at 11:49





















                                                    • Note that this will create a JSONEncoder object every time you call this property. FYI options: .allowFragments is pointless and can just be omitted. Btw your approach would be much easier if you encode your date as a single element collection.

                                                      – Leo Dabus
                                                      Feb 6 at 11:17











                                                    • extension JSONEncoder { static let iso8601: JSONEncoder = { let iso8601 = JSONEncoder() iso8601.dateEncodingStrategy = .iso8601 return iso8601 }() } extension Date { var isoString: String { return (try! JSONSerialization.jsonObject(with: JSONEncoder.iso8601.encode([self])) as! [String]).first! } } and don't worry about forcing unwrap, it will never fail in this case.

                                                      – Leo Dabus
                                                      Feb 6 at 11:18













                                                    • Another option when using the array approach is to drop the first and last 2 bytes of the encoded data and convert the subdata to string. extension Date { var isoString: String { return try! String(data: JSONEncoder.iso8601.encode([self])[2..<22], encoding: .utf8)! } }

                                                      – Leo Dabus
                                                      Feb 6 at 11:49



















                                                    Note that this will create a JSONEncoder object every time you call this property. FYI options: .allowFragments is pointless and can just be omitted. Btw your approach would be much easier if you encode your date as a single element collection.

                                                    – Leo Dabus
                                                    Feb 6 at 11:17





                                                    Note that this will create a JSONEncoder object every time you call this property. FYI options: .allowFragments is pointless and can just be omitted. Btw your approach would be much easier if you encode your date as a single element collection.

                                                    – Leo Dabus
                                                    Feb 6 at 11:17













                                                    extension JSONEncoder { static let iso8601: JSONEncoder = { let iso8601 = JSONEncoder() iso8601.dateEncodingStrategy = .iso8601 return iso8601 }() } extension Date { var isoString: String { return (try! JSONSerialization.jsonObject(with: JSONEncoder.iso8601.encode([self])) as! [String]).first! } } and don't worry about forcing unwrap, it will never fail in this case.

                                                    – Leo Dabus
                                                    Feb 6 at 11:18







                                                    extension JSONEncoder { static let iso8601: JSONEncoder = { let iso8601 = JSONEncoder() iso8601.dateEncodingStrategy = .iso8601 return iso8601 }() } extension Date { var isoString: String { return (try! JSONSerialization.jsonObject(with: JSONEncoder.iso8601.encode([self])) as! [String]).first! } } and don't worry about forcing unwrap, it will never fail in this case.

                                                    – Leo Dabus
                                                    Feb 6 at 11:18















                                                    Another option when using the array approach is to drop the first and last 2 bytes of the encoded data and convert the subdata to string. extension Date { var isoString: String { return try! String(data: JSONEncoder.iso8601.encode([self])[2..<22], encoding: .utf8)! } }

                                                    – Leo Dabus
                                                    Feb 6 at 11:49







                                                    Another option when using the array approach is to drop the first and last 2 bytes of the encoded data and convert the subdata to string. extension Date { var isoString: String { return try! String(data: JSONEncoder.iso8601.encode([self])[2..<22], encoding: .utf8)! } }

                                                    – Leo Dabus
                                                    Feb 6 at 11:49




















                                                    draft saved

                                                    draft discarded




















































                                                    Thanks for contributing an answer to Stack Overflow!


                                                    • Please be sure to answer the question. Provide details and share your research!

                                                    But avoid



                                                    • Asking for help, clarification, or responding to other answers.

                                                    • Making statements based on opinion; back them up with references or personal experience.


                                                    To learn more, see our tips on writing great answers.




                                                    draft saved


                                                    draft discarded














                                                    StackExchange.ready(
                                                    function () {
                                                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f28016578%2fhow-to-create-a-date-time-stamp-and-format-as-iso-8601-rfc-3339-utc-time-zone%23new-answer', 'question_page');
                                                    }
                                                    );

                                                    Post as a guest















                                                    Required, but never shown





















































                                                    Required, but never shown














                                                    Required, but never shown












                                                    Required, but never shown







                                                    Required, but never shown

































                                                    Required, but never shown














                                                    Required, but never shown












                                                    Required, but never shown







                                                    Required, but never shown







                                                    這個網誌中的熱門文章

                                                    Hercules Kyvelos

                                                    Tangent Lines Diagram Along Smooth Curve

                                                    Yusuf al-Mu'taman ibn Hud