如何使用ISO 8601RFC 3339的格式标准生成日期时间戳?

目标是一个如下所示的字符串:

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

格式:

  • 年、月、日,如"XXXX-XX-XX"
  • 字母"T"作为分隔符
  • 小时、分钟、秒、毫秒,表示为"XX:XX:XX.XXX".
  • 字母"Z"作为零偏移的区域指示符,又称UTC、GMT、祖鲁时间.

最佳 case :

  • Swift源代码,简单、简短、直截了当.
  • 无需使用任何额外的框架、子项目、cocoapod、C代码等.

我搜索了StackOverflow、谷歌、苹果等,但没有找到快速的答案.

最有希望的课程是NSDateNSDateFormatterNSTimeZone.

相关问题;A:How do I get an ISO 8601 date on iOS?

以下是我迄今为止提出的最好的建议:

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) }
}

用法:

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\n"
}

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

如果在使用Codable时需要对该格式进行编码和解码

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
    }
}

以及编码策略

extension JSONEncoder.DateEncodingStrategy {
    static let iso8601withFractionalSeconds = custom {
        var container = $1.singleValueContainer()
        try container.encode(Formatter.iso8601withFractionalSeconds.string(from: $0))
    }
}

操场测试

let dates = [Date()]   // ["Feb 8, 2019 at 9:48 PM"]

编码

let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601withFractionalSeconds
let data = try! encoder.encode(dates)
print(String(data: data, 编码: .utf8)!)

解码

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

enter image description here

Swift相关问答推荐

带有文本输入自动大小写修饰符的SwiftUI Textfield问题

如何将CodingKeys作为数组而不是枚举传递到类外部的函数中?

将`@Environment`值赋给`Binding`参数

像WebSocket一样接收实时更新,但通过异步/等待或组合

将NavigationSplitView更改为NavigationStack

如何在 SwiftUI 中为过渡动画保持相同的标识

macOS 的窗口框架中使用的真实类型和真实类型是什么?

使第二个视图变灰 SwiftUI

如何制作进度加载动画?

一组可散列的自定义元素插入相等的元素

Swiftui 按钮依次显示一组图像

在 SwiftUI 中的 ForEach 中使用 id 时如何为数组设置动画索引

如何在填充上添加 if else 语句? SwiftUI

在 Swift 5.5 中编写同步和异步函数

仅在 Swift 中创建 Setter

在 Xcode 中自动实现 Swift 协议方法

Swift:在子类中覆盖 == 导致仅在超类中调用 ==

Swift 中的 PageViewController 当前页面索引

由于编译器中的内部保护级别,无法访问框架 init 中的公共 struct

Swift - 迭代 struct 对象时如何对其进行变异