forked from swiftlang/swift-corelibs-foundation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathISO8601DateFormatter.swift
157 lines (112 loc) · 6.31 KB
/
ISO8601DateFormatter.swift
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
157
// 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
//
import CoreFoundation
extension ISO8601DateFormatter {
public struct Options : OptionSet {
public private(set) var rawValue: UInt
public init(rawValue: UInt) { self.rawValue = rawValue }
public static var withYear = ISO8601DateFormatter.Options(rawValue: 1 << 0)
public static var withMonth = ISO8601DateFormatter.Options(rawValue: 1 << 1)
public static var withWeekOfYear = ISO8601DateFormatter.Options(rawValue: 1 << 2)
public static var withDay = ISO8601DateFormatter.Options(rawValue: 1 << 4)
public static var withTime = ISO8601DateFormatter.Options(rawValue: 1 << 5)
public static var withTimeZone = ISO8601DateFormatter.Options(rawValue: 1 << 6)
public static var withSpaceBetweenDateAndTime = ISO8601DateFormatter.Options(rawValue: 1 << 7)
public static var withDashSeparatorInDate = ISO8601DateFormatter.Options(rawValue: 1 << 8)
public static var withColonSeparatorInTime = ISO8601DateFormatter.Options(rawValue: 1 << 9)
public static var withColonSeparatorInTimeZone = ISO8601DateFormatter.Options(rawValue: 1 << 10)
public static var withFractionalSeconds = ISO8601DateFormatter.Options(rawValue: 1 << 11)
public static var withFullDate = ISO8601DateFormatter.Options(rawValue: withYear.rawValue + withMonth.rawValue + withDay.rawValue + withDashSeparatorInDate.rawValue)
public static var withFullTime = ISO8601DateFormatter.Options(rawValue: withTime.rawValue + withTimeZone.rawValue + withColonSeparatorInTime.rawValue + withColonSeparatorInTimeZone.rawValue)
public static var withInternetDateTime = ISO8601DateFormatter.Options(rawValue: withFullDate.rawValue + withFullTime.rawValue)
}
}
open class ISO8601DateFormatter : Formatter, NSSecureCoding {
typealias CFType = CFDateFormatter
private var __cfObject: CFType?
private var _cfObject: CFType {
guard let obj = __cfObject else {
#if os(macOS) || os(iOS)
let format = CFISO8601DateFormatOptions(rawValue: formatOptions.rawValue)
#else
let format = CFISO8601DateFormatOptions(self.formatOptions.rawValue)
#endif
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")
}
}
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 {
#if os(macOS) || os(iOS)
let format = CFISO8601DateFormatOptions(rawValue: formatOptions.rawValue)
#else
let format = CFISO8601DateFormatOptions(formatOptions.rawValue)
#endif
let obj = CFDateFormatterCreateISO8601Formatter(kCFAllocatorSystemDefault, format)
CFDateFormatterSetProperty(obj, kCFDateFormatterTimeZone, timeZone._cfObject)
return CFDateFormatterCreateStringWithDate(kCFAllocatorSystemDefault, obj, date._cfObject)._swiftObject
}
private func _reset() {
__cfObject = nil
}
}