File: Time.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 (159 lines) | stat: -rw-r--r-- 4,884 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
157
158
159
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCertificates open source project
//
// Copyright (c) 2022-2023 Apple Inc. and the SwiftCertificates project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftCertificates project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import Foundation
import SwiftASN1

// Time ::= CHOICE {
// utcTime        UTCTime,
// generalTime    GeneralizedTime }
@usableFromInline
enum Time: DERParseable, DERSerializable, Hashable, Sendable {
    case utcTime(UTCTime)
    case generalTime(GeneralizedTime)

    @inlinable
    init(derEncoded rootNode: ASN1Node) throws {
        switch rootNode.identifier {
        case GeneralizedTime.defaultIdentifier:
            self = .generalTime(try GeneralizedTime(derEncoded: rootNode))
        case UTCTime.defaultIdentifier:
            self = .utcTime(try UTCTime(derEncoded: rootNode))
        default:
            throw ASN1Error.unexpectedFieldType(rootNode.identifier)
        }
    }

    @inlinable
    func serialize(into coder: inout DER.Serializer) throws {
        switch self {
        case .utcTime(let utcTime):
            try coder.serialize(utcTime)
        case .generalTime(let generalizedTime):
            try coder.serialize(generalizedTime)
        }
    }

    @inlinable
    static func makeTime(from date: Date) throws -> Time {
        let components = date.utcDate

        // The rule is if the year is outside the range 1950-2049 inclusive, we should encode
        // it as a generalized time. Otherwise, use a UTCTime.
        guard ((1950)..<(2050)).contains(components.year) else {
            let generalizedTime = try GeneralizedTime(components)
            return .generalTime(generalizedTime)
        }
        let utcTime = try UTCTime(components)
        return .utcTime(utcTime)
    }
}

extension Date {
    @inlinable
    init(fromUTCDate date: (year: Int, month: Int, day: Int, hours: Int, minutes: Int, seconds: Int)) {
        let timestamp = Int64(timestampFromUTCDate: date)
        self = .init(timeIntervalSince1970: TimeInterval(timestamp))
    }

    @inlinable
    var utcDate: (year: Int, month: Int, day: Int, hours: Int, minutes: Int, seconds: Int) {
        let timestamp = Int64(self.timeIntervalSince1970.rounded())
        return timestamp.utcDateFromTimestamp
    }

    @inlinable
    init(_ time: Time) {
        switch time {
        case .generalTime(let generalizedTime):
            self = .init(generalizedTime)
        case .utcTime(let utcTime):
            self = .init(utcTime)
        }
    }

    @inlinable
    init(_ time: GeneralizedTime) {
        self = Date(
            fromUTCDate: (
                year: time.year, month: time.month, day: time.day, hours: time.hours, minutes: time.minutes,
                seconds: time.seconds
            )
        )
    }

    @inlinable
    init(_ time: UTCTime) {
        self = Date(
            fromUTCDate: (
                year: time.year, month: time.month, day: time.day, hours: time.hours, minutes: time.minutes,
                seconds: time.seconds
            )
        )
    }
}

extension GeneralizedTime {
    @inlinable
    init(_ time: Time) {
        switch time {
        case .generalTime(let t):
            self = t
        case .utcTime(let t):
            // This can never throw, all valid UTCTimes are valid GeneralizedTimes
            self = try! GeneralizedTime(
                year: t.year,
                month: t.month,
                day: t.day,
                hours: t.hours,
                minutes: t.minutes,
                seconds: t.seconds,
                fractionalSeconds: 0
            )
        }
    }

    @inlinable
    init(_ components: (year: Int, month: Int, day: Int, hours: Int, minutes: Int, seconds: Int)) throws {
        try self.init(
            year: components.year,
            month: components.month,
            day: components.day,
            hours: components.hours,
            minutes: components.minutes,
            seconds: components.seconds,
            fractionalSeconds: 0.0
        )
    }

    @inlinable
    init(_ date: Date) {
        // This cannot throw: any valid Date can be represented.
        try! self.init(date.utcDate)
    }
}

extension UTCTime {
    @inlinable
    init(_ components: (year: Int, month: Int, day: Int, hours: Int, minutes: Int, seconds: Int)) throws {
        try self.init(
            year: components.year,
            month: components.month,
            day: components.day,
            hours: components.hours,
            minutes: components.minutes,
            seconds: components.seconds
        )
    }
}