ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) ve RFC 3339 format standartlarını kullanarak bir tarih saat damgası nasıl oluşturulur?
Hedef, aşağıdaki gibi görünen bir dizedir:
"2015-01-01T00:00:00.000Z"
Format:
En iyi durum:
StackOverflow'u, Google'ı, Apple'ı vb. araştırdım ve buna bir Swift yanıtı bulamadım.
En umut verici görünen sınıflar NSDate
, NSDateFormatter
, NSTimeZone
.
İlgili Soru ve Cevaplar: https://stackoverflow.com/questions/16254575/how-do-i-get-iso-8601-date-in-ios
İşte şimdiye kadar bulduklarımın en iyisi:
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))
Swift 4 - iOS 11.2.1 veya üstü
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)
}
}
Kullanım:
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.746Z\n"
}
iOS 9 - Swift 3 veya üstü
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
}()
}
Kodlanabilir Protokol
Codable ile çalışırken bu formatı kodlamanız ve kodunu çözmeniz gerekiyorsa protokolü ile kendi özel tarih kodlama/kod çözme stratejilerinizi oluşturabilirsiniz:
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
}
}
ve kodlama stratejisi
extension JSONEncoder.DateEncodingStrategy {
static let iso8601withFractionalSeconds = custom {
var container = $1.singleValueContainer()
try container.encode(Formatter.iso8601.string(from: $0))
}
}
Oyun Alanı Testi
let dates = [Date()] // ["Feb 8, 2019 at 9:48 PM"]
kodlama
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601withFractionalSeconds
let data = try! encoder.encode(dates)
print(String(data: data, encoding: .utf8)!)
kod çözme
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 8, 2019 at 9:48 PM"]
Yerel ayarı Technical Q&A1480 adresinde açıklandığı gibi en_US_POSIX
olarak ayarlamayı unutmayın. Swift 3'te
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))
Sorun şu ki, eğer Gregoryen olmayan bir takvim kullanan bir cihaz kullanıyorsanız, locale
ile birlikte timeZone
ve dateFormat
dizelerini belirtmediğiniz sürece yıl RFC3339/ISO8601 ile uyumlu olmayacaktır.
Ya da locale
ve timeZone
ayarlarını kendiniz yapmaktan kurtulmak için ISO8601DateFormatter
kullanabilirsiniz:
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))
Swift 2 yorumu için bakınız bu cevabın önceki revizyonu.
Benim durumumda DynamoDB - lastUpdated sütununu (Unix Timestamp) Normal Zamana dönüştürmem gerekiyor.
lastUpdated'in ilk değeri : 1460650607601 idi - 2016-04-14 16:16:47 +0000 aracılığıyla aşağıya dönüştürüldü:
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)
}