joe*_*son 172 time date iso8601 rfc3339 swift
如何使用ISO 8601和RFC 3339的格式标准生成日期时间戳?
目标是一个如下所示的字符串:
"2015-01-01T00:00:00.000Z"
Run Code Online (Sandbox Code Playgroud)
格式:
最佳案例:
我搜索过StackOverflow,Google,Apple等,并没有找到Swift的答案.
似乎最有前途的类NSDate,NSDateFormatter,NSTimeZone.
相关问答:如何在iOS中获得ISO 8601日期?
这是迄今为止我提出的最好的:
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))
Run Code Online (Sandbox Code Playgroud)
Leo*_*bus 361
Xcode 9•Swift 4•iOS 11或更高版本
extension ISO8601DateFormatter {
convenience init(_ formatOptions: Options, timeZone: TimeZone = TimeZone(secondsFromGMT: 0)!) {
self.init()
self.formatOptions = formatOptions
self.timeZone = timeZone
}
}
Run Code Online (Sandbox Code Playgroud)
extension Formatter {
static let iso8601 = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])
}
Run Code Online (Sandbox Code Playgroud)
extension Date {
var iso8601: String {
return Formatter.iso8601.string(from: self)
}
}
Run Code Online (Sandbox Code Playgroud)
extension String {
var iso8601: Date? {
return Formatter.iso8601.date(from: self)
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
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"
}
Run Code Online (Sandbox Code Playgroud)
iOS 9•Swift 3或更高版本
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
}()
}
Run Code Online (Sandbox Code Playgroud)
可编程协议
如果在使用Codable协议时需要对此格式进行编码和解码,则可以创建自己的自定义日期编码/解码策略:
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
}
}
Run Code Online (Sandbox Code Playgroud)
和编码策略
extension JSONEncoder.DateEncodingStrategy {
static let iso8601withFractionalSeconds = custom {
var container = $1.singleValueContainer()
try container.encode(Formatter.iso8601.string(from: $0))
}
}
Run Code Online (Sandbox Code Playgroud)
游乐场测试
let dates = [Date()] // ["Feb 8, 2019 at 9:48 PM"]
Run Code Online (Sandbox Code Playgroud)
编码
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601withFractionalSeconds
let data = try! encoder.encode(dates)
print(String(data: data, encoding: .utf8)!)
Run Code Online (Sandbox Code Playgroud)
解码
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 8, 2019 at 9:48 PM"]
Run Code Online (Sandbox Code Playgroud)
Rob*_*Rob 34
请记住将技术语言设置en_US_POSIX为技术问答1480中所述.在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))
Run Code Online (Sandbox Code Playgroud)
问题是,如果你是其中使用非公历的设备上,今年不会,除非你指定符合RFC3339/ISO8601 locale还有timeZone和dateFormat字符串.
或者你可以ISO8601DateFormatter用来让你摆脱设置locale和timeZone自己的杂草:
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))
Run Code Online (Sandbox Code Playgroud)
对于Swift 2的演绎,请参阅此答案的上一版本.
Mat*_*ong 23
如果你想使用ISO8601DateFormatter()带有Rails 4+ JSON提要的日期(当然不需要毫秒),你需要在格式化程序上设置一些选项才能正常工作,否则该date(from: string)函数将返回nil.这是我正在使用的:
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
}()
}
Run Code Online (Sandbox Code Playgroud)
以下是使用操场截图中不包含选项的结果:
jrc*_*jrc 16
如果你的目标的iOS 11.0+ / MacOS的10.13+,您只需使用ISO8601DateFormatter与withInternetDateTime和withFractionalSeconds选项,如下所示:
let date = Date()
let iso8601DateFormatter = ISO8601DateFormatter()
iso8601DateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let string = iso8601DateFormatter.string(from: date)
// string looks like "2020-03-04T21:39:02.112Z"
Run Code Online (Sandbox Code Playgroud)
为了进一步赞美 Andrés Torres Marroquín 和 Leo Dabus,我有一个保留小数秒的版本。我在任何地方都找不到它的记录,但 Apple 将输入和输出的小数秒截断为微秒(3 位精度)(即使使用 SSSSSSS 指定,与Unicode tr35-31相反)。
我应该强调,这对于大多数用例来说可能不是必需的。在线日期通常不需要毫秒精度,当需要时,最好使用不同的数据格式。但有时必须以特定方式与预先存在的系统进行互操作。
Xcode 8/9 和 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
}
}
Run Code Online (Sandbox Code Playgroud)
用途ISO8601DateFormatter上iOS10或更高版本。
用途DateFormatter上iOS9或以上。
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
}
}()
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
101988 次 |
| 最近记录: |