How to create a date time stamp and format as ISO 8601, RFC 3339, UTC time zone?
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
add a comment |
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
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
add a comment |
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
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
date swift time iso8601 rfc3339
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
add a comment |
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
add a comment |
10 Answers
10
active
oldest
votes
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"]
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 10ISO8601DateFormatter
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
|
show 9 more comments
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.
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 byen_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 useen_US_POSIX
and noten_US
). See Technical Q&A 1480 or those RFC/ISO standards for more information.
– Rob
Dec 13 '17 at 10:23
add a comment |
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:
You would need to include in the options also the.withFractionalSeconds
but I already tried that and it keeps throwing an errorlibc++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
|
show 1 more comment
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
}
}
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
add a comment |
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)
}
add a comment |
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
}
}
}
add a comment |
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)
}
}
}
add a comment |
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
}
}()
}
add a comment |
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
}
}
add a comment |
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
Note that this will create aJSONEncoder
object every time you call this property. FYIoptions: .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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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"]
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 10ISO8601DateFormatter
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
|
show 9 more comments
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"]
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 10ISO8601DateFormatter
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
|
show 9 more comments
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"]
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"]
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 10ISO8601DateFormatter
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
|
show 9 more comments
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 10ISO8601DateFormatter
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
|
show 9 more comments
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.
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 byen_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 useen_US_POSIX
and noten_US
). See Technical Q&A 1480 or those RFC/ISO standards for more information.
– Rob
Dec 13 '17 at 10:23
add a comment |
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.
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 byen_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 useen_US_POSIX
and noten_US
). See Technical Q&A 1480 or those RFC/ISO standards for more information.
– Rob
Dec 13 '17 at 10:23
add a comment |
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.
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.
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 byen_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 useen_US_POSIX
and noten_US
). See Technical Q&A 1480 or those RFC/ISO standards for more information.
– Rob
Dec 13 '17 at 10:23
add a comment |
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 byen_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 useen_US_POSIX
and noten_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
add a comment |
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:
You would need to include in the options also the.withFractionalSeconds
but I already tried that and it keeps throwing an errorlibc++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
|
show 1 more comment
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:
You would need to include in the options also the.withFractionalSeconds
but I already tried that and it keeps throwing an errorlibc++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
|
show 1 more comment
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:
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:
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 errorlibc++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
|
show 1 more comment
You would need to include in the options also the.withFractionalSeconds
but I already tried that and it keeps throwing an errorlibc++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
|
show 1 more comment
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
}
}
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
add a comment |
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
}
}
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
add a comment |
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
}
}
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
}
}
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
add a comment |
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
add a comment |
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)
}
add a comment |
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)
}
add a comment |
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)
}
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)
}
answered Apr 15 '16 at 11:09
iooplioopl
1,3721416
1,3721416
add a comment |
add a comment |
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
}
}
}
add a comment |
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
}
}
}
add a comment |
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
}
}
}
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
}
}
}
edited Dec 5 '16 at 3:57
answered Dec 5 '16 at 3:13
Gary DaviesGary Davies
56289
56289
add a comment |
add a comment |
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)
}
}
}
add a comment |
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)
}
}
}
add a comment |
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)
}
}
}
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)
}
}
}
answered Jun 28 '17 at 15:35
Thomas SzaboThomas Szabo
884
884
add a comment |
add a comment |
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
}
}()
}
add a comment |
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
}
}()
}
add a comment |
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
}
}()
}
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
}
}()
}
answered Mar 8 '18 at 13:14
neoneyeneoneye
31.1k19132124
31.1k19132124
add a comment |
add a comment |
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
}
}
add a comment |
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
}
}
add a comment |
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
}
}
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
}
}
answered Nov 3 '16 at 16:22
Andrés Torres MarroquínAndrés Torres Marroquín
1,5561212
1,5561212
add a comment |
add a comment |
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
Note that this will create aJSONEncoder
object every time you call this property. FYIoptions: .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
add a comment |
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
Note that this will create aJSONEncoder
object every time you call this property. FYIoptions: .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
add a comment |
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
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
answered Dec 4 '18 at 5:33
Dmitrii ZDmitrii Z
8913
8913
Note that this will create aJSONEncoder
object every time you call this property. FYIoptions: .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
add a comment |
Note that this will create aJSONEncoder
object every time you call this property. FYIoptions: .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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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