File: ISO8601DateFormatter.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (156 lines) | stat: -rw-r--r-- 6,475 bytes parent folder | download
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
    }
    
}