1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
@_implementationOnly import CoreFoundation
extension ISO8601DateFormatter {
public struct Options : OptionSet, Sendable {
public private(set) var rawValue: UInt
public init(rawValue: UInt) { self.rawValue = rawValue }
public static let withYear = ISO8601DateFormatter.Options(rawValue: 1 << 0)
public static let withMonth = ISO8601DateFormatter.Options(rawValue: 1 << 1)
public static let withWeekOfYear = ISO8601DateFormatter.Options(rawValue: 1 << 2)
public static let withDay = ISO8601DateFormatter.Options(rawValue: 1 << 4)
public static let withTime = ISO8601DateFormatter.Options(rawValue: 1 << 5)
public static let withTimeZone = ISO8601DateFormatter.Options(rawValue: 1 << 6)
public static let withSpaceBetweenDateAndTime = ISO8601DateFormatter.Options(rawValue: 1 << 7)
public static let withDashSeparatorInDate = ISO8601DateFormatter.Options(rawValue: 1 << 8)
public static let withColonSeparatorInTime = ISO8601DateFormatter.Options(rawValue: 1 << 9)
public static let withColonSeparatorInTimeZone = ISO8601DateFormatter.Options(rawValue: 1 << 10)
public static let withFractionalSeconds = ISO8601DateFormatter.Options(rawValue: 1 << 11)
public static let withFullDate = ISO8601DateFormatter.Options(rawValue: withYear.rawValue + withMonth.rawValue + withDay.rawValue + withDashSeparatorInDate.rawValue)
public static let withFullTime = ISO8601DateFormatter.Options(rawValue: withTime.rawValue + withTimeZone.rawValue + withColonSeparatorInTime.rawValue + withColonSeparatorInTimeZone.rawValue)
public static let withInternetDateTime = ISO8601DateFormatter.Options(rawValue: withFullDate.rawValue + withFullTime.rawValue)
}
}
@available(*, unavailable)
extension ISO8601DateFormatter : @unchecked Sendable { }
open class ISO8601DateFormatter : Formatter, NSSecureCoding {
typealias CFType = CFDateFormatter
private final var __cfObject: CFType?
private final var _cfObject: CFType {
guard let obj = __cfObject else {
let format = CFISO8601DateFormatOptions(rawValue: formatOptions.rawValue)
let obj = CFDateFormatterCreateISO8601Formatter(kCFAllocatorSystemDefault, format)!
CFDateFormatterSetProperty(obj, kCFDateFormatterTimeZone, timeZone._cfObject)
__cfObject = obj
return obj
}
return obj
}
/* Please note that there can be a significant performance cost when resetting these properties. Resetting each property can result in regenerating the entire CFDateFormatterRef, which can be very expensive. */
open var timeZone: TimeZone! { willSet { _reset() } }
open var formatOptions: ISO8601DateFormatter.Options { willSet { _reset() } }
public override init() {
timeZone = TimeZone(identifier: "GMT")
formatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withColonSeparatorInTimeZone]
super.init()
}
public required init?(coder aDecoder: NSCoder) {
guard aDecoder.allowsKeyedCoding else {
fatalError("Decoding ISO8601DateFormatter requires a coder that allows keyed coding")
}
self.formatOptions = Options(rawValue: UInt(aDecoder.decodeInteger(forKey: "NS.formatOptions")))
let timeZone: NSTimeZone?
if aDecoder.containsValue(forKey: "NS.timeZone") {
if let tz = aDecoder.decodeObject(of: NSTimeZone.self, forKey: "NS.timeZone") {
timeZone = tz
} else {
aDecoder.failWithError(CocoaError(.coderReadCorrupt, userInfo: [ NSLocalizedDescriptionKey: "Time zone was corrupt while decoding ISO8601DateFormatter" ]))
return nil
}
} else {
timeZone = nil
}
if let zone = timeZone?._swiftObject {
self.timeZone = zone
}
super.init()
}
open override func encode(with aCoder: NSCoder) {
guard aCoder.allowsKeyedCoding else {
fatalError("Encoding ISO8601DateFormatter requires a coder that allows keyed coding")
}
aCoder.encode(Int(formatOptions.rawValue), forKey: "NS.formatOptions")
if let timeZone = timeZone {
aCoder.encode(timeZone._nsObject, forKey: "NS.timeZone")
}
}
open override func copy(with zone: NSZone? = nil) -> Any {
let copied = ISO8601DateFormatter()
copied.timeZone = timeZone
copied.formatOptions = formatOptions
return copied
}
public static var supportsSecureCoding: Bool { return true }
open func string(from date: Date) -> String {
return CFDateFormatterCreateStringWithDate(kCFAllocatorSystemDefault, _cfObject, date._cfObject)._swiftObject
}
open func date(from string: String) -> Date? {
var range = CFRange(location: 0, length: string.length)
let date = withUnsafeMutablePointer(to: &range) { (rangep: UnsafeMutablePointer<CFRange>) -> Date? in
guard let res = CFDateFormatterCreateDateFromString(kCFAllocatorSystemDefault, _cfObject, string._cfObject, rangep) else {
return nil
}
return res._swiftObject
}
return date
}
open class func string(from date: Date, timeZone: TimeZone, formatOptions: ISO8601DateFormatter.Options = []) -> String {
let format = CFISO8601DateFormatOptions(rawValue: formatOptions.rawValue)
let obj = CFDateFormatterCreateISO8601Formatter(kCFAllocatorSystemDefault, format)
CFDateFormatterSetProperty(obj, kCFDateFormatterTimeZone, timeZone._cfObject)
return CFDateFormatterCreateStringWithDate(kCFAllocatorSystemDefault, obj, date._cfObject)._swiftObject
}
private func _reset() {
__cfObject = nil
}
}
|