File: DateAdditions.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 (140 lines) | stat: -rw-r--r-- 5,005 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
//===--------------- DateAdditions.swift - Swift Date Additions -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#if os(Windows)
import WinSDK
#elseif os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(Musl)
import Musl
#elseif canImport(Bionic)
import Bionic
#endif

/// Represents a time point value with nanosecond precision.
///
/// - Warning: The accuracy of measured `TimePoint` values is an OS-dependent property.
///            `TimePoint` does not correct for OS-level differences in e.g.
///             clock epochs. This makes it unsuitable for serialization in
///             products that are expected to transit between machines.
public struct TimePoint: Equatable, Comparable, Hashable {
  public var seconds: UInt64
  public var nanoseconds: UInt32

  public init(seconds: UInt64, nanoseconds: UInt32) {
    self.seconds = seconds
    self.nanoseconds = nanoseconds
  }

  public static func < (lhs: TimePoint, rhs: TimePoint) -> Bool {
    return (lhs.seconds, lhs.nanoseconds) < (rhs.seconds, rhs.nanoseconds)
  }
}

extension TimePoint {
  public static func seconds(_ value: Int64) -> TimePoint {
    precondition(value >= 0,
                 "Duration value in seconds is \(value), but cannot be negative")
    return TimePoint(seconds: UInt64(value), nanoseconds: 0)
  }

  public static func nanoseconds(_ value: Int) -> TimePoint {
    precondition(value >= 0,
                 "Duration value in nanoseconds is \(value), but cannot be negative")
    let (seconds, nanos) = value.quotientAndRemainder(dividingBy: TimePoint.nanosecondsPerSecond)
    return TimePoint(seconds: UInt64(seconds),
                     nanoseconds: UInt32(nanos))
  }
}

extension TimePoint: AdditiveArithmetic {
  public static var zero: TimePoint {
    return .seconds(0)
  }

  public static func + (lhs: TimePoint, rhs: TimePoint) -> TimePoint {
    // Add raw operands
    var seconds = lhs.seconds + rhs.seconds
    var nanos = lhs.nanoseconds + rhs.nanoseconds
    // Normalize nanoseconds
    if nanos >= TimePoint.nanosecondsPerSecond {
      nanos -= UInt32(TimePoint.nanosecondsPerSecond)
      seconds += 1
    }
    return TimePoint(seconds: seconds, nanoseconds: nanos)
  }

  public static func - (lhs: TimePoint, rhs: TimePoint) -> TimePoint {
    // Subtract raw operands
    var seconds = lhs.seconds - rhs.seconds
    // Normalize nanoseconds
    let nanos: UInt32
    if lhs.nanoseconds >= rhs.nanoseconds {
      nanos = lhs.nanoseconds - rhs.nanoseconds
    } else {
      // Subtract nanoseconds with carry - order of operations here
      // is important to avoid overflow.
      nanos = lhs.nanoseconds + UInt32(TimePoint.nanosecondsPerSecond) - rhs.nanoseconds
      seconds -= 1
    }
    return TimePoint(seconds: seconds, nanoseconds: nanos)
  }
}

extension TimePoint{
  public static func now() -> TimePoint {
    #if os(Windows)
    var ftTime: FILETIME = FILETIME()
    GetSystemTimePreciseAsFileTime(&ftTime)

    let result: UInt64 = (UInt64(ftTime.dwLowDateTime) << 0)
                       + (UInt64(ftTime.dwHighDateTime) << 32)
    // Windows ticks in 100 nanosecond intervals.
    return .seconds(Int64(result / 10_000_000))
    #else
    var tv = timeval()
    gettimeofday(&tv, nil)
    return TimePoint(seconds: UInt64(tv.tv_sec),
                     nanoseconds: UInt32(tv.tv_usec) * UInt32(Self.nanosecondsPerMicrosecond))
    #endif
  }

  public static var distantPast: TimePoint {
    return .zero
  }

  public static var distantFuture: TimePoint {
    // N.B. This is the seconds value of `Foundation.Date.distantFuture.timeIntervalSince1970`.
    // At time of writing, this is January 1, 4001 at 12:00:00 AM GMT, which is
    // far enough in the future that it's a reasonable time point for us to
    // compare against.
    //
    // However, it is important to note that Foundation's value cannot be both
    // fixed in time AND correct because of leap seconds and other calendrical
    // oddities.
    //
    // Other candidates include std::chrono's std::time_point::max - which is
    // about 9223372036854775807 - enough to comfortably bound the age of the
    // universe.
    return .seconds(64_092_211_200)
  }
}

extension TimePoint {
  fileprivate static let nanosecondsPerSecond: Int = 1_000_000_000
  fileprivate static let nanosecondsPerMillisecond: Int = 1_000_000
  fileprivate static let nanosecondsPerMicrosecond: Int = 1_000
  fileprivate static let millisecondsPerSecond: Int = 1_000
  fileprivate static let microsecondsPerSecond: Int = 1_000_000
}