如何在 Swift 中解析/创建格式化为 UTC 时区(ISO 8601、RFC 3339)的小数秒格式的日期时间戳? [英] How can I parse / create a date time stamp formatted with fractional seconds UTC timezone (ISO 8601, RFC 3339) in Swift?
问题描述
如何使用ISO 8601和<的格式标准生成日期时间戳a href="https://www.rfc-editor.org/rfc/rfc3339" rel="nofollow noreferrer">RFC 3339?
目标是一个看起来像这样的字符串:
2015-01-01T00:00:00.000Z"
格式:
- 年、月、日,如XXXX-XX-XX"
- 字母T"作为分隔符
- 时、分、秒、毫秒,如XX:XX:XX.XXX".
- 字母Z"作为零偏移的区域指示符,也就是 UTC、GMT、祖鲁时间.
最佳情况:
- 简单、简短且直接的 Swift 源代码.
- 无需使用任何额外的框架、子项目、cocoapod、C 代码等.
我搜索了 StackOverflow、Google、Apple 等,但没有找到 Swift 的答案.
看起来最有前途的类是 NSDate
, NSDateFormatter
, NSTimeZone
.
这是我目前想到的最好的:
var now = NSDate()var 格式化程序 = 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 或更高版本
扩展 ISO8601DateFormatter {方便初始化(_格式选项:选项){self.init()self.formatOptions = formatOptions}}
extension Formatter {静态 let iso8601withFractionalSeconds = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])}
延期日期{var iso8601withFractionalSeconds: String { return Formatter.iso8601withFractionalSeconds.string(from: self) }}
扩展字符串{var iso8601withFractionalSeconds:日期?{ 返回 Formatter.iso8601withFractionalSeconds.date(from: self) }}
用法:
Date().description(with: .current)//2019 年 2 月 5 日,星期二,巴西利亚夏令时间晚上 10:35:01"let dateString = Date().iso8601withFractionalSeconds//2019-02-06T00:35:01.746Z"如果让日期 = dateString.iso8601withFractionalSeconds {date.description(with: .current)//巴西利亚夏令时间,2019 年 2 月 5 日星期二晚上 10:35:01"打印(date.iso8601withFractionalSeconds)//2019-02-06T00:35:01.746Z
"}
iOS 9 • Swift 3 或更高版本
extension Formatter {静态 let iso8601withFractionalSeconds: DateFormatter = {让格式化程序 = DateFormatter()formatter.calendar = 日历(标识符:.iso8601)formatter.locale = Locale(标识符:en_US_POSIX")formatter.timeZone = TimeZone(secondsFromGMT: 0)formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX";返回格式化程序}()}
<块引用>
可编码协议
如果在使用 Codable 时需要对这种格式进行编码和解码协议,您可以创建自己的自定义日期编码/解码策略:
extension JSONDecoder.DateDecodingStrategy {静态让 iso8601withFractionalSeconds = 自定义 {让容器 = 尝试 $0.singleValueContainer()让字符串 = 尝试 container.decode(String.self)守卫让日期 = Formatter.iso8601withFractionalSeconds.date(from: string) else {抛出 DecodingError.dataCorruptedError(in: 容器,调试说明:无效日期:"+ 字符串)}归期}}
和编码策略
extension JSONEncoder.DateEncodingStrategy {静态让 iso8601withFractionalSeconds = 自定义 {var 容器 = $1.singleValueContainer()试试 container.encode(Formatter.iso8601withFractionalSeconds.string(from: $0))}}
游乐场测试
let dates = [Date()]//[2019 年 2 月 8 日晚上 9:48"]
编码
让编码器 = JSONEncoder()编码器.dateEncodingStrategy = .iso8601withFractionalSeconds让数据=尝试!编码器.编码(日期)打印(字符串(数据:数据,编码:.utf8)!)
解码
让解码器 = JSONDecoder()解码器.dateDecodingStrategy = .iso8601withFractionalSeconds让decodedDates = 试试!decoder.decode([Date].self, from: data)//[2019 年 2 月 8 日晚上 9:48"]
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 an ISO 8601 date on 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))
Swift 4 • iOS 11.2.1 or later
extension ISO8601DateFormatter {
convenience init(_ formatOptions: Options) {
self.init()
self.formatOptions = formatOptions
}
}
extension Formatter {
static let iso8601withFractionalSeconds = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])
}
extension Date {
var iso8601withFractionalSeconds: String { return Formatter.iso8601withFractionalSeconds.string(from: self) }
}
extension String {
var iso8601withFractionalSeconds: Date? { return Formatter.iso8601withFractionalSeconds.date(from: self) }
}
Usage:
Date().description(with: .current) // Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
let dateString = Date().iso8601withFractionalSeconds // "2019-02-06T00:35:01.746Z"
if let date = dateString.iso8601withFractionalSeconds {
date.description(with: .current) // "Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
print(date.iso8601withFractionalSeconds) // "2019-02-06T00:35:01.746Z
"
}
iOS 9 • Swift 3 or later
extension Formatter {
static let iso8601withFractionalSeconds: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
return formatter
}()
}
Codable Protocol
If you need to encode and decode this format when working with Codable protocol you can create your own custom date encoding/decoding strategies:
extension JSONDecoder.DateDecodingStrategy {
static let iso8601withFractionalSeconds = custom {
let container = try $0.singleValueContainer()
let string = try container.decode(String.self)
guard let date = Formatter.iso8601withFractionalSeconds.date(from: string) else {
throw DecodingError.dataCorruptedError(in: container,
debugDescription: "Invalid date: " + string)
}
return date
}
}
and the encoding strategy
extension JSONEncoder.DateEncodingStrategy {
static let iso8601withFractionalSeconds = custom {
var container = $1.singleValueContainer()
try container.encode(Formatter.iso8601withFractionalSeconds.string(from: $0))
}
}
Playground Testing
let dates = [Date()] // ["Feb 8, 2019 at 9:48 PM"]
encoding
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601withFractionalSeconds
let data = try! encoder.encode(dates)
print(String(data: data, encoding: .utf8)!)
decoding
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 8, 2019 at 9:48 PM"]
这篇关于如何在 Swift 中解析/创建格式化为 UTC 时区(ISO 8601、RFC 3339)的小数秒格式的日期时间戳?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!