From 58a3f8aa75a2e460b7b833048f90932b94520ef4 Mon Sep 17 00:00:00 2001 From: T Liu Date: Fri, 7 Nov 2025 09:32:34 -0800 Subject: [PATCH] Revert "128-bit Date (#3475)" (#3549) Reverting this from main for now to figure out test breakages --- Sources/FoundationEssentials/CMakeLists.txt | 1 - .../Calendar/Calendar_Gregorian.swift | 29 +-- .../Calendar/Calendar_Recurrence.swift | 17 +- Sources/FoundationEssentials/Date.swift | 97 ++------- .../FoundationEssentials/DateInterval.swift | 49 ++--- .../FoundationEssentials/DoubleDouble.swift | 186 ------------------ .../GregorianCalendarTests.swift | 27 +-- .../CalendarTests.swift | 2 +- .../ParseStrategy+RegexComponentTests.swift | 5 +- ...ianCalendarInternationalizationTests.swift | 76 +++---- 10 files changed, 97 insertions(+), 392 deletions(-) delete mode 100644 Sources/FoundationEssentials/DoubleDouble.swift diff --git a/Sources/FoundationEssentials/CMakeLists.txt b/Sources/FoundationEssentials/CMakeLists.txt index 36b6e34cb..a5a1e9c79 100644 --- a/Sources/FoundationEssentials/CMakeLists.txt +++ b/Sources/FoundationEssentials/CMakeLists.txt @@ -21,7 +21,6 @@ add_library(FoundationEssentials ComparisonResult.swift Date.swift DateInterval.swift - DoubleDouble.swift FoundationEssentials.swift IndexPath.swift LockedState.swift diff --git a/Sources/FoundationEssentials/Calendar/Calendar_Gregorian.swift b/Sources/FoundationEssentials/Calendar/Calendar_Gregorian.swift index 4f5cc4885..b7809b9b0 100644 --- a/Sources/FoundationEssentials/Calendar/Calendar_Gregorian.swift +++ b/Sources/FoundationEssentials/Calendar/Calendar_Gregorian.swift @@ -1448,39 +1448,30 @@ internal final class _CalendarGregorian: _CalendarProtocol, @unchecked Sendable } func dateInterval(of component: Calendar.Component, for date: Date) -> DateInterval? { - let approximateTime = date._time.head + let time = date.timeIntervalSinceReferenceDate var effectiveUnit = component switch effectiveUnit { case .calendar, .timeZone, .isLeapMonth, .isRepeatedDay: return nil case .era: - if approximateTime < -63113904000.0 { + if time < -63113904000.0 { return DateInterval(start: Date(timeIntervalSinceReferenceDate: -63113904000.0 - inf_ti), duration: inf_ti) } else { return DateInterval(start: Date(timeIntervalSinceReferenceDate: -63113904000.0), duration: inf_ti) } case .hour: - // Local hours may not be aligned to GMT hours, so we have to apply - // the time zone adjustment before rounding down, then unapply it. - let offset = Double(timeZone.secondsFromGMT(for: date)) - let start = ((date._time + offset)/3600).floor() * 3600 - offset - return DateInterval( - start: Date(start), - duration: 3600 - ) + let ti = Double(timeZone.secondsFromGMT(for: date)) + var fixedTime = time + ti // compute local time + fixedTime = floor(fixedTime / 3600.0) * 3600.0 + fixedTime = fixedTime - ti // compute GMT + return DateInterval(start: Date(timeIntervalSinceReferenceDate: fixedTime), duration: 3600.0) case .minute: - return DateInterval( - start: Date((date._time/60).floor() * 60), - duration: 60 - ) + return DateInterval(start: Date(timeIntervalSinceReferenceDate: floor(time / 60.0) * 60.0), duration: 60.0) case .second: - return DateInterval(start: Date(date._time.floor()), duration: 1) + return DateInterval(start: Date(timeIntervalSinceReferenceDate: floor(time)), duration: 1.0) case .nanosecond: - return DateInterval( - start: Date((date._time*1e9).floor() / 1e9), - duration: 1e-9 - ) + return DateInterval(start: Date(timeIntervalSinceReferenceDate: floor(time * 1.0e+9) * 1.0e-9), duration: 1.0e-9) case .year, .yearForWeekOfYear, .quarter, .month, .day, .dayOfYear, .weekOfMonth, .weekOfYear: // Continue to below break diff --git a/Sources/FoundationEssentials/Calendar/Calendar_Recurrence.swift b/Sources/FoundationEssentials/Calendar/Calendar_Recurrence.swift index 8d9a32abc..dd8740236 100644 --- a/Sources/FoundationEssentials/Calendar/Calendar_Recurrence.swift +++ b/Sources/FoundationEssentials/Calendar/Calendar_Recurrence.swift @@ -93,8 +93,8 @@ extension Calendar { /// value is used as a lower bound for ``nextBaseRecurrenceDate()``. let rangeLowerBound: Date? - /// The start date's fractional seconds component - let fractionalSeconds: TimeInterval + /// The start date's nanoseconds component + let startDateNanoseconds: TimeInterval /// How many occurrences have been found so far var resultsFound = 0 @@ -131,10 +131,7 @@ extension Calendar { } self.recurrence = recurrence - // round start down to whole seconds, set aside fraction. - let wholeSeconds = start._time.floor() - fractionalSeconds = (start._time - wholeSeconds).head - self.start = Date(wholeSeconds) + self.start = start self.range = range let frequency = recurrence.frequency @@ -236,7 +233,9 @@ extension Calendar { case .monthly: [.second, .minute, .hour, .day] case .yearly: [.second, .minute, .hour, .day, .month, .isLeapMonth] } - var componentsForEnumerating = recurrence.calendar._dateComponents(components, from: start) + var componentsForEnumerating = recurrence.calendar._dateComponents(components, from: start) + + startDateNanoseconds = start.timeIntervalSinceReferenceDate.truncatingRemainder(dividingBy: 1) let expansionChangesDay = dayOfYearAction == .expand || dayOfMonthAction == .expand || weekAction == .expand || weekdayAction == .expand let expansionChangesMonth = dayOfYearAction == .expand || monthAction == .expand || weekAction == .expand @@ -428,11 +427,11 @@ extension Calendar { recurrence._limitTimeComponent(.second, dates: &dates, anchor: anchor) } - if fractionalSeconds != 0 { + if startDateNanoseconds > 0 { // `_dates(startingAfter:)` above returns whole-second dates, // so we need to restore the nanoseconds value present in the original start date. for idx in dates.indices { - dates[idx] += fractionalSeconds + dates[idx] += startDateNanoseconds } } dates = dates.filter { $0 >= self.start } diff --git a/Sources/FoundationEssentials/Date.swift b/Sources/FoundationEssentials/Date.swift index 2fefd10fc..df240ed2f 100644 --- a/Sources/FoundationEssentials/Date.swift +++ b/Sources/FoundationEssentials/Date.swift @@ -34,64 +34,12 @@ public typealias TimeInterval = Double A `Date` is independent of a particular calendar or time zone. To represent a `Date` to a user, you must interpret it in the context of a `Calendar`. */ @available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *) -public struct Date: Comparable, Hashable, Equatable, Sendable { - /* Date is internally represented as a sum of two Doubles. - - Previously Date was backed by a single Double measuring time since - Jan 1 2001 in seconds. Because Double's precision is non-uniform, this - means that times within a hundred days of the epoch are represented - with approximately nanosecond precision, but as you get farther away - from that date the precision decreases. For times close to the time - at which this comment was written, accuracy has been reduced to about - 100ns. - - The obvious thing would be to adopt an integer-based representation - similar to C's timespec (32b nanoseconds, 64b seconds) or Swift's - Duration (128b attoseconds). These representations suffer from a few - difficulties: - - - Existing API on Date takes and produces `TimeInterval` (aka Double). - Making Date use an integer representation internally would mean that - existing users of the public API would suddently start getting - different results for computations that were previously exact; even - though we could add new API, and the overall system would be more - precise, this would be a surprisingly subtle change for users to - navigate. - - - We have been told that some software interprets the raw bytes of Date - as a Double for the purposes of fast serialization. These packages - formally violate Foundation's API boundaries, but that doesn't help - users of those packages who would abruptly be broken by switching to - an integer representation. - - Using DoubleDouble instead navigates these problems fairly elegantly. - - - Because DoubleDouble is still a floating-point type, it still suffers - from non-uniform precision. However, because DoubleDouble is so - fantastically precise, it can represent dates out to ±2.5 quadrillion - years at ~nanosecond or better precision, so in practice this won't - be much of an issue. - - - Existing API on Date will produce exactly the same result as it did - previously in cases where those results were exact, minimizing - surprises. In cases where the existing API was not exact, it will - produce much more accurate results, even if users do not adopt new - API, because its internal calculations are now more precise. - - - Software that (incorrectly) interprets the raw bytes of Date as a - Double will get at least as accurate of a value as it did previously - (and often a more accurate value). */ - internal var _time: DoubleDouble - - internal init(_ time: DoubleDouble) { - self._time = time - } -} +public struct Date : Comparable, Hashable, Equatable, Sendable { + + internal var _time : TimeInterval -@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *) -extension Date { /// The number of seconds from 1 January 1970 to the reference date, 1 January 2001. - public static let timeIntervalBetween1970AndReferenceDate: TimeInterval = 978307200.0 + public static let timeIntervalBetween1970AndReferenceDate : TimeInterval = 978307200.0 /// The number of seconds from 1 January 1601 to the reference date, 1 January 2001. internal static let timeIntervalBetween1601AndReferenceDate: TimeInterval = 12622780800.0 @@ -103,23 +51,17 @@ extension Date { /// Returns a `Date` initialized to the current date and time. public init() { - _time = .init(uncheckedHead: Self.getCurrentAbsoluteTime(), tail: 0) + _time = Self.getCurrentAbsoluteTime() } /// Returns a `Date` initialized relative to the current date and time by a given number of seconds. public init(timeIntervalSinceNow: TimeInterval) { - self.init(.sum( - Self.getCurrentAbsoluteTime(), - timeIntervalSinceNow - )) + self.init(timeIntervalSinceReferenceDate: timeIntervalSinceNow + Self.getCurrentAbsoluteTime()) } /// Returns a `Date` initialized relative to 00:00:00 UTC on 1 January 1970 by a given number of seconds. public init(timeIntervalSince1970: TimeInterval) { - self.init(.sum( - timeIntervalSince1970, - -Date.timeIntervalBetween1970AndReferenceDate - )) + self.init(timeIntervalSinceReferenceDate: timeIntervalSince1970 - Date.timeIntervalBetween1970AndReferenceDate) } /** @@ -129,12 +71,12 @@ extension Date { - Parameter date: The reference date. */ public init(timeInterval: TimeInterval, since date: Date) { - self.init(date._time + timeInterval) + self.init(timeIntervalSinceReferenceDate: date.timeIntervalSinceReferenceDate + timeInterval) } /// Returns a `Date` initialized relative to 00:00:00 UTC on 1 January 2001 by a given number of seconds. public init(timeIntervalSinceReferenceDate ti: TimeInterval) { - _time = .init(uncheckedHead: ti, tail: 0) + _time = ti } /** @@ -143,7 +85,7 @@ extension Date { This property's value is negative if the date object is earlier than the system's absolute reference date (00:00:00 UTC on 1 January 2001). */ public var timeIntervalSinceReferenceDate: TimeInterval { - return _time.head + return _time } /** @@ -158,7 +100,7 @@ extension Date { - SeeAlso: `timeIntervalSinceReferenceDate` */ public func timeIntervalSince(_ date: Date) -> TimeInterval { - return (self._time - date._time).head + return self.timeIntervalSinceReferenceDate - date.timeIntervalSinceReferenceDate } /** @@ -231,9 +173,9 @@ extension Date { /// Compare two `Date` values. public func compare(_ other: Date) -> ComparisonResult { - if _time < other._time { + if _time < other.timeIntervalSinceReferenceDate { return .orderedAscending - } else if _time > other._time { + } else if _time > other.timeIntervalSinceReferenceDate { return .orderedDescending } else { return .orderedSame @@ -242,27 +184,27 @@ extension Date { /// Returns true if the two `Date` values represent the same point in time. public static func ==(lhs: Date, rhs: Date) -> Bool { - return lhs._time == rhs._time + return lhs.timeIntervalSinceReferenceDate == rhs.timeIntervalSinceReferenceDate } /// Returns true if the left hand `Date` is earlier in time than the right hand `Date`. public static func <(lhs: Date, rhs: Date) -> Bool { - return lhs._time < rhs._time + return lhs.timeIntervalSinceReferenceDate < rhs.timeIntervalSinceReferenceDate } /// Returns true if the left hand `Date` is later in time than the right hand `Date`. public static func >(lhs: Date, rhs: Date) -> Bool { - return lhs._time > rhs._time + return lhs.timeIntervalSinceReferenceDate > rhs.timeIntervalSinceReferenceDate } /// Returns a `Date` with a specified amount of time added to it. public static func +(lhs: Date, rhs: TimeInterval) -> Date { - return Date(lhs._time + rhs) + return Date(timeIntervalSinceReferenceDate: lhs.timeIntervalSinceReferenceDate + rhs) } /// Returns a `Date` with a specified amount of time subtracted from it. public static func -(lhs: Date, rhs: TimeInterval) -> Date { - return Date(lhs._time - rhs) + return Date(timeIntervalSinceReferenceDate: lhs.timeIntervalSinceReferenceDate - rhs) } /// Add a `TimeInterval` to a `Date`. @@ -278,6 +220,7 @@ extension Date { public static func -=(lhs: inout Date, rhs: TimeInterval) { lhs = lhs - rhs } + } @available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *) @@ -395,7 +338,7 @@ extension Date : ReferenceConvertible, _ObjectiveCBridgeable { @_semantics("convertToObjectiveC") public func _bridgeToObjectiveC() -> NSDate { - return NSDate(timeIntervalSinceReferenceDate: _time.head) + return NSDate(timeIntervalSinceReferenceDate: _time) } public static func _forceBridgeFromObjectiveC(_ x: NSDate, result: inout Date?) { diff --git a/Sources/FoundationEssentials/DateInterval.swift b/Sources/FoundationEssentials/DateInterval.swift index 835157808..04d2c55d1 100644 --- a/Sources/FoundationEssentials/DateInterval.swift +++ b/Sources/FoundationEssentials/DateInterval.swift @@ -12,37 +12,30 @@ /// DateInterval represents a closed date interval in the form of [startDate, endDate]. It is possible for the start and end dates to be the same with a duration of 0. DateInterval does not support reverse intervals i.e. intervals where the duration is less than 0 and the end date occurs earlier in time than the start date. @available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -public struct DateInterval: Comparable, Hashable, Codable, Sendable { +public struct DateInterval : Comparable, Hashable, Codable, Sendable { /// The start date. - public var start: Date - - /// Underlying storage for `duration` - internal var _duration: DoubleDouble + public var start : Date /// The end date. /// /// - precondition: `end >= start` - public var end: Date { + public var end : Date { get { - return Date(start._time + _duration) + return start + duration } set { precondition(newValue >= start, "Reverse intervals are not allowed") - _duration = (newValue._time - start._time) + duration = newValue.timeIntervalSinceReferenceDate - start.timeIntervalSinceReferenceDate } } - - /// The duration + + /// The duration. /// /// - precondition: `duration >= 0` - public var duration: TimeInterval { - get { - _duration.head - } - set { + public var duration : TimeInterval { + willSet { precondition(newValue >= 0, "Negative durations are not allowed") - _duration = DoubleDouble(uncheckedHead: newValue, tail: 0) } } @@ -50,7 +43,7 @@ public struct DateInterval: Comparable, Hashable, Codable, Sendable { public init() { let d = Date() start = d - _duration = .zero + duration = 0 } /// Initialize a `DateInterval` with the specified start and end date. @@ -59,7 +52,7 @@ public struct DateInterval: Comparable, Hashable, Codable, Sendable { public init(start: Date, end: Date) { precondition(end >= start, "Reverse intervals are not allowed") self.start = start - _duration = end._time - start._time + duration = end.timeIntervalSince(start) } /// Initialize a `DateInterval` with the specified start date and duration. @@ -68,7 +61,7 @@ public struct DateInterval: Comparable, Hashable, Codable, Sendable { public init(start: Date, duration: TimeInterval) { precondition(duration >= 0, "Negative durations are not allowed") self.start = start - _duration = DoubleDouble(uncheckedHead: duration, tail: 0) + self.duration = duration } /** @@ -169,24 +162,6 @@ public struct DateInterval: Comparable, Hashable, Codable, Sendable { public static func <(lhs: DateInterval, rhs: DateInterval) -> Bool { return lhs.compare(rhs) == .orderedAscending } - - enum CodingKeys: String, CodingKey { - case start = "start" - case duration = "duration" - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let start = try container.decode(Date.self, forKey: .start) - let duration = try container.decode(TimeInterval.self, forKey: .duration) - self.init(start: start, duration: duration) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(start, forKey: .start) - try container.encode(duration, forKey: .duration) - } } @available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) diff --git a/Sources/FoundationEssentials/DoubleDouble.swift b/Sources/FoundationEssentials/DoubleDouble.swift deleted file mode 100644 index b8d58ddf4..000000000 --- a/Sources/FoundationEssentials/DoubleDouble.swift +++ /dev/null @@ -1,186 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2025 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 -// -//===----------------------------------------------------------------------===// - -/// A numeric type that uses two Double values as its representation, providing -/// about 106 bits of precision with the same exponent range as Double. -/// -/// This type conforms to AdditiveArithmetic, Hashable and Comparable, but does -/// not conform to FloatingPoint or Numeric; it implements only the API surface -/// that is necessary to serve as an internal implementation detail of Date. -internal struct DoubleDouble { - - private let storage: (Double, Double) - - /// A double-double value constructed by specifying the head and tail. - /// - /// This is an unchecked operation because it does not enforce the - /// invariant that head + tail == head in release builds, which is - /// necessary for subsequent arithmetic operations to behave correctly. - @_transparent - init(uncheckedHead head: Double, tail: Double) { - assert(!head.isFinite || head + tail == head) - storage = (head, tail) - } - - /// The high-order Double. - /// - /// This property does not have a setter because `head` should pretty much - /// never be set independently of `tail`, so as to maintain the invariant - /// that `head + tail == head`. You can use `init(uncheckedHead:tail:)` - /// to directly construct DoubleDouble values, which will enforce the - /// invariant in debug builds. - @_transparent - var head: Double { storage.0 } - - /// The low-order Double. - /// - /// This property does not have a setter because `tail` should pretty much - /// never be set independently of `head`, so as to maintain the invariant - /// that `head + tail == head`. You can use `init(uncheckedHead:tail:)` - /// to directly construct DoubleDouble values, which will enforce the - /// invariant in debug builds. - @_transparent - var tail: Double { storage.1 } - - /// `a + b` represented as a normalized DoubleDouble. - /// - /// Computed via the [2Sum algorithm](https://en.wikipedia.org/wiki/2Sum). - @inlinable - static func sum(_ a: Double, _ b: Double) -> DoubleDouble { - let head = a + b - let x = head - b - let y = head - x - let tail = (a - x) + (b - y) - return DoubleDouble(uncheckedHead: head, tail: tail) - } - - /// `a + b` represented as a normalized DoubleDouble. - /// - /// Computed via the [Fast2Sum algorithm](https://en.wikipedia.org/wiki/2Sum). - /// - /// - Precondition: - /// `large` and `small` must be such that `sum(large:small:)` - /// produces the same result as `sum(_:_:)` would. A sufficient condition - /// is that `|large| >= |small|`, but this is not necessary, so we do not - /// enforce it via an assert. Instead this function asserts that the result - /// is the same as that produced by `sum(_:_:)` in Debug builds. This is - /// unchecked in Release. - @inlinable - static func sum(large a: Double, small b: Double) -> DoubleDouble { - let head = a + b - let tail = a - head + b - let result = DoubleDouble(uncheckedHead: head, tail: tail) - assert(!head.isFinite || result == sum(a, b)) - return result - } - - /// `a * b` represented as a normalized DoubleDouble. - @inlinable - static func product(_ a: Double, _ b: Double) -> DoubleDouble { - let head = a * b - let tail = (-head).addingProduct(a, b) - return DoubleDouble(uncheckedHead: head, tail: tail) - } -} - -extension DoubleDouble: Comparable { - @_transparent - static func ==(a: Self, b: Self) -> Bool { - a.head == b.head && a.tail == b.tail - } - - @_transparent - static func <(a: Self, b: Self) -> Bool { - a.head < b.head || a.head == b.head && a.tail < b.tail - } -} - -extension DoubleDouble: Hashable { - @_transparent - func hash(into hasher: inout Hasher) { - hasher.combine(head) - hasher.combine(tail) - } -} - -extension DoubleDouble: AdditiveArithmetic { - @inlinable - static var zero: DoubleDouble { - Self(uncheckedHead: 0, tail: 0) - } - - @inlinable - static func +(a: DoubleDouble, b: DoubleDouble) -> DoubleDouble { - let heads = sum(a.head, b.head) - let tails = sum(a.tail, b.tail) - let first = sum(large: heads.head, small: heads.tail + tails.head) - return sum(large: first.head, small: first.tail + tails.tail) - } - - /// Equivalent to `a + DoubleDouble(uncheckedHead: b, tail: 0)` but - /// computed more efficiently. - @inlinable - static func +(a: DoubleDouble, b: Double) -> DoubleDouble { - let heads = sum(a.head, b) - let first = sum(large: heads.head, small: heads.tail + a.tail) - return sum(large: first.head, small: first.tail) - } - - @inlinable - prefix static func -(a: DoubleDouble) -> DoubleDouble { - DoubleDouble(uncheckedHead: -a.head, tail: -a.tail) - } - - @inlinable - static func -(a: DoubleDouble, b: DoubleDouble) -> DoubleDouble { - a + (-b) - } - - /// Equivalent to `a - DoubleDouble(uncheckedHead: b, tail: 0)` but - /// computed more efficiently. - @inlinable - static func -(a: DoubleDouble, b: Double) -> DoubleDouble { - a + (-b) - } -} - -extension DoubleDouble { - @inlinable - static func *(a: DoubleDouble, b: Double) -> DoubleDouble { - let tmp = product(a.head, b) - return DoubleDouble( - uncheckedHead: tmp.head, - tail: tmp.tail.addingProduct(a.tail, b) - ) - } - - @inlinable - static func /(a: DoubleDouble, b: Double) -> DoubleDouble { - let head = a.head/b - let residual = a.head.addingProduct(-head, b) + a.tail - return .sum(large: head, small: residual/b) - } -} - -extension DoubleDouble { - // This value rounded down to an integer. - @inlinable - func floor() -> DoubleDouble { - let approx = head.rounded(.down) - // If head was already an integer, round tail down and renormalize. - if approx == head { - return .sum(large: head, small: tail.rounded(.down)) - } - // Head was not an integer; we can simply discard tail. - return DoubleDouble(uncheckedHead: approx, tail: 0) - } -} diff --git a/Tests/FoundationEssentialsTests/GregorianCalendarTests.swift b/Tests/FoundationEssentialsTests/GregorianCalendarTests.swift index 31377c924..9e3d3c05f 100644 --- a/Tests/FoundationEssentialsTests/GregorianCalendarTests.swift +++ b/Tests/FoundationEssentialsTests/GregorianCalendarTests.swift @@ -277,13 +277,7 @@ private struct GregorianCalendarTests { func test(addField field: Calendar.Component, value: Int, to addingToDate: Date, wrap: Bool, expectedDate: Date, sourceLocation: SourceLocation = #_sourceLocation) { let components = DateComponents(component: field, value: value)! let result = gregorianCalendar.date(byAdding: components, to: addingToDate, wrappingComponents: wrap)! - // These tests were written when Date used a 64b representation; - // we'll add new tests that validate the low-word of the 128b - // Date, but these old tests should continue passing if we only - // look at the high word as vended by tISRD. - #expect(result.timeIntervalSinceReferenceDate == - expectedDate.timeIntervalSinceReferenceDate, - sourceLocation: sourceLocation) + #expect(result == expectedDate, sourceLocation: sourceLocation) } date = Date(timeIntervalSince1970: 825723300.0) @@ -405,13 +399,7 @@ private struct GregorianCalendarTests { func test(addField field: Calendar.Component, value: Int, to addingToDate: Date, wrap: Bool, expectedDate: Date, sourceLocation: SourceLocation = #_sourceLocation) { let components = DateComponents(component: field, value: value)! let result = gregorianCalendar.date(byAdding: components, to: addingToDate, wrappingComponents: wrap)! - // These tests were written when Date used a 64b representation; - // we'll add new tests that validate the low-word of the 128b - // Date, but these old tests should continue passing if we only - // look at the high word as vended by tISRD. - #expect(result.timeIntervalSinceReferenceDate == - expectedDate.timeIntervalSinceReferenceDate, - sourceLocation: sourceLocation) + #expect(result == expectedDate, sourceLocation: sourceLocation) } date = Date(timeIntervalSince1970: 62135596800.0) // 3939-01-01 @@ -838,11 +826,7 @@ private struct GregorianCalendarTests { let new_end = new?.end #expect(new_start == start, "interval start did not match", sourceLocation: sourceLocation) - // These tests were written when Date used a 64b representation; - // we'll add new tests that validate the low-word of the 128b - // Date, but these old tests should continue passing if we only - // look at the high word as vended by tISRD. - #expect(new_end?.timeIntervalSinceReferenceDate == end?.timeIntervalSinceReferenceDate, "interval end did not match", sourceLocation: sourceLocation) + #expect(new_end == end, "interval end did not match", sourceLocation: sourceLocation) } var date: Date @@ -854,10 +838,7 @@ private struct GregorianCalendarTests { test(.hour, date, expectedStart: Date(timeIntervalSince1970: 820454400.0), end: Date(timeIntervalSince1970: 820458000.0)) test(.minute, date, expectedStart: Date(timeIntervalSince1970: 820454400.0), end: Date(timeIntervalSince1970: 820454460.0)) test(.second, date, expectedStart: Date(timeIntervalSince1970: 820454400.0), end: Date(timeIntervalSince1970: 820454401.0)) - // Legacy test from 64b Date; expected end is the same as start due to rounding. test(.nanosecond, date, expectedStart: Date(timeIntervalSince1970: 820454400.0), end: Date(timeIntervalSince1970: 820454400.0)) - // Updated test for 128b Date to benefit from improved accuracy: - #expect(calendar.dateInterval(of: .nanosecond, for: date)?.end == Date(timeInterval: 1e-9, since: date)) test(.weekday, date, expectedStart: Date(timeIntervalSince1970: 820396800.0), end: Date(timeIntervalSince1970: 820483200.0)) test(.weekdayOrdinal, date, expectedStart: Date(timeIntervalSince1970: 820396800.0), end: Date(timeIntervalSince1970: 820483200.0)) test(.quarter, date, expectedStart: Date(timeIntervalSince1970: 812534400.0), end: Date(timeIntervalSince1970: 820483200.0)) @@ -888,7 +869,7 @@ private struct GregorianCalendarTests { test(.hour, date, expectedStart: Date(timeIntervalSince1970: -62135769600.0), end: Date(timeIntervalSince1970: -62135766000.0)) test(.minute, date, expectedStart: Date(timeIntervalSince1970: -62135769600.0), end: Date(timeIntervalSince1970: -62135769540.0)) test(.second, date, expectedStart: Date(timeIntervalSince1970: -62135769600.0), end: Date(timeIntervalSince1970: -62135769599.0)) - test(.nanosecond, date, expectedStart: date, end: Date(timeInterval: 1e-9, since: date)) + test(.nanosecond, date, expectedStart: Date(timeIntervalSince1970: -62135769600.00001), end: Date(timeIntervalSince1970: -62135769600.00001)) test(.weekday, date, expectedStart: Date(timeIntervalSince1970: -62135827200.0), end: Date(timeIntervalSince1970: -62135740800.0)) test(.weekdayOrdinal, date, expectedStart: Date(timeIntervalSince1970: -62135827200.0), end: Date(timeIntervalSince1970: -62135740800.0)) test(.quarter, date, expectedStart: Date(timeIntervalSince1970: -62143689600.0), end: Date(timeIntervalSince1970: -62135740800.0)) diff --git a/Tests/FoundationInternationalizationTests/CalendarTests.swift b/Tests/FoundationInternationalizationTests/CalendarTests.swift index 6ce160945..8602f9a26 100644 --- a/Tests/FoundationInternationalizationTests/CalendarTests.swift +++ b/Tests/FoundationInternationalizationTests/CalendarTests.swift @@ -1420,7 +1420,7 @@ private struct CalendarTests { func test(_ start: Date, _ end: Date) throws { let components = c.dateComponents([.year, .month, .day, .hour, .minute, .second, .nanosecond, .weekOfMonth], from: start, to: end) let added = try #require(c.date(byAdding: components, to: start)) - #expect(added.timeIntervalSinceReferenceDate == end.timeIntervalSinceReferenceDate, "actual: \(s.format(added)), expected: \(s.format(end))") + #expect(added == end, "actual: \(s.format(added)), expected: \(s.format(end))") } // 2024-03-09T02:34:36-0800, 2024-03-17T03:34:36-0700, 10:34:36 UTC diff --git a/Tests/FoundationInternationalizationTests/Formatting/ParseStrategy+RegexComponentTests.swift b/Tests/FoundationInternationalizationTests/Formatting/ParseStrategy+RegexComponentTests.swift index f9370c88d..6e684a957 100644 --- a/Tests/FoundationInternationalizationTests/Formatting/ParseStrategy+RegexComponentTests.swift +++ b/Tests/FoundationInternationalizationTests/Formatting/ParseStrategy+RegexComponentTests.swift @@ -62,6 +62,8 @@ private struct ParseStrategyMatchTests { #expect(res.output.1 == expectedDate) } +// https://github.com/apple/swift-foundation/issues/60 +#if FOUNDATION_FRAMEWORK @Test func apiStatement() { let statement = """ @@ -211,8 +213,9 @@ DEBIT Mar 31/20 March Payment to BoA -USD 52,249.98 #expect(match.output.1 == "MergeableSetTests") #expect(match.output.2 == "started") // dateFormatter.date(from: "2021-07-08 10:19:35.418")! - #expect(match.output.3.timeIntervalSinceReferenceDate == 647432375.418) + #expect(match.output.3 == Date(timeIntervalSinceReferenceDate: 647432375.418)) } +#endif @Test func variousDatesAndTimes() { func verify(_ str: String, _ strategy: Date.ParseStrategy, _ expected: String?, sourceLocation: SourceLocation = #_sourceLocation) { diff --git a/Tests/FoundationInternationalizationTests/GegorianCalendarInternationalizationTests.swift b/Tests/FoundationInternationalizationTests/GegorianCalendarInternationalizationTests.swift index 3d389281c..195c18912 100644 --- a/Tests/FoundationInternationalizationTests/GegorianCalendarInternationalizationTests.swift +++ b/Tests/FoundationInternationalizationTests/GegorianCalendarInternationalizationTests.swift @@ -1461,8 +1461,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828262987.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 829468987.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828262987.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 828867787.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828867787.0)) date = Date(timeIntervalSince1970: 828871387.0) // 1996-04-07T03:03:07-0700 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 828871387.0)) @@ -1489,8 +1489,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828270187.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 829476187.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828270187.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 828871387.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828871387.0)) date = Date(timeIntervalSince1970: 828874987.0) // 1996-04-07T04:03:07-0700 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 828874987.0)) @@ -1517,8 +1517,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828273787.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 829479787.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828273787.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 828874987.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828874987.0)) date = Date(timeIntervalSince1970: 846403387.0) // 1996-10-27T01:03:07-0700 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846403387.0)) @@ -1547,8 +1547,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845798587.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 847011787.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845798587.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846403387.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 846403387.0)) date = Date(timeIntervalSince1970: 846406987.0) // 1996-10-27T01:03:07-0800 // Previously this returns 1996-10-27T01:03:07-0700 @@ -1578,8 +1578,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845798587.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 847011787.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845798587.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846406987.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 846406987.0)) date = Date(timeIntervalSince1970: 846410587.0) // 1996-10-27T02:03:07-0800 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846410587.0)) @@ -1606,8 +1606,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845802187.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 847015387.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845802187.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846410587.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 846410587.0)) date = Date(timeIntervalSince1970: 846414187.0) // 1996-10-27T03:03:07-0800 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846414187.0)) @@ -1634,8 +1634,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845805787.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 847018987.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845805787.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846414187.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 846414187.0)) date = Date(timeIntervalSince1970: 814953787.0) // 1995-10-29T01:03:07-0700 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 814953787.0)) @@ -1664,8 +1664,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814348987.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 815562187.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814348987.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 814953787.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814953787.0)) date = Date(timeIntervalSince1970: 814957387.0) // 1995-10-29T01:03:07-0800 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 814957387.0)) @@ -1692,8 +1692,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814348987.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 815562187.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814348987.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 814957387.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814957387.0)) date = Date(timeIntervalSince1970: 814960987.0) // 1995-10-29T02:03:07-0800 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 814960987.0)) @@ -1720,8 +1720,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814352587.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 815565787.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814352587.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 814960987.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814960987.0)) date = Date(timeIntervalSince1970: 814964587.0) // 1995-10-29T03:03:07-0800 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 814964587.0)) @@ -1748,8 +1748,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814356187.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 815569387.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814356187.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 814964587.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 814964587.0)) } @Test func add_Wrap_DST() { @@ -1789,8 +1789,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828262987.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 829468987.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 830851387.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 828867787.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828867787.0)) date = Date(timeIntervalSince1970: 828871387.0) // 1996-04-07T03:03:07-0700 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 828871387.0)) @@ -1817,8 +1817,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828270187.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 829476187.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 830858587.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 828871387.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828871387.0)) date = Date(timeIntervalSince1970: 828874987.0) // 1996-04-07T04:03:07-0700 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 828874987.0)) @@ -1845,8 +1845,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828273787.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 829479787.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 830862187.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 828874987.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 828874987.0)) date = Date(timeIntervalSince1970: 846406987.0) // 1996-10-27T01:03:07-0800 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846406987.0)) @@ -1873,8 +1873,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845798587.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846752587.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845798587.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846406987.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 846406987.0)) date = Date(timeIntervalSince1970: 846410587.0) // 1996-10-27T02:03:07-0800 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846410587.0)) @@ -1901,8 +1901,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845802187.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846756187.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845802187.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846410587.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 846410587.0)) date = Date(timeIntervalSince1970: 846414187.0) // 1996-10-27T03:03:07-0800 test(addField: .era, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846414187.0)) @@ -1929,8 +1929,8 @@ private struct GregorianCalendarInternationalizationTests { test(addField: .weekOfYear, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845805787.0)) test(addField: .weekOfMonth, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846759787.0)) test(addField: .weekOfMonth, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 845805787.0)) - test(addField: .nanosecond, value: 1, to: date, expectedDate: date.addingTimeInterval(1e-9)) - test(addField: .nanosecond, value: -1, to: date, expectedDate: date.addingTimeInterval(-1e-9)) + test(addField: .nanosecond, value: 1, to: date, expectedDate: Date(timeIntervalSince1970: 846414187.0)) + test(addField: .nanosecond, value: -1, to: date, expectedDate: Date(timeIntervalSince1970: 846414187.0)) } @Test func ordinality_DST() { @@ -2448,21 +2448,21 @@ private struct GregorianCalendarInternationalizationTests { dc_customCalendarAndTimeZone.timeZone = .init(secondsFromGMT: 28800) // calendar.timeZone = UTC+0, dc.calendar.timeZone = UTC-7, dc.timeZone = UTC+8 // expect local time in dc.timeZone (UTC+8) - #expect(gregorianCalendar.date(from: dc_customCalendarAndTimeZone)!.timeIntervalSinceReferenceDate == 679024975.891) // 2022-07-09T02:02:55Z + #expect(gregorianCalendar.date(from: dc_customCalendarAndTimeZone)! == Date(timeIntervalSinceReferenceDate: 679024975.891)) // 2022-07-09T02:02:55Z var dc_customCalendar = dc dc_customCalendar.calendar = dcCalendar dc_customCalendar.timeZone = nil // calendar.timeZone = UTC+0, dc.calendar.timeZone = UTC-7, dc.timeZone = nil // expect local time in calendar.timeZone (UTC+0) - #expect(gregorianCalendar.date(from: dc_customCalendar)!.timeIntervalSinceReferenceDate == 679053775.891) // 2022-07-09T10:02:55Z + #expect(gregorianCalendar.date(from: dc_customCalendar)! == Date(timeIntervalSinceReferenceDate: 679053775.891)) // 2022-07-09T10:02:55Z var dc_customTimeZone = dc_customCalendarAndTimeZone dc_customTimeZone.calendar = nil dc_customTimeZone.timeZone = .init(secondsFromGMT: 28800) // calendar.timeZone = UTC+0, dc.calendar = nil, dc.timeZone = UTC+8 // expect local time in dc.timeZone (UTC+8) - #expect(gregorianCalendar.date(from: dc_customTimeZone)!.timeIntervalSinceReferenceDate == 679024975.891) // 2022-07-09T02:02:55Z + #expect(gregorianCalendar.date(from: dc_customTimeZone)! == Date(timeIntervalSinceReferenceDate: 679024975.891)) // 2022-07-09T02:02:55Z let dcCalendar_noTimeZone = Calendar(identifier: .japanese, locale: Locale(identifier: ""), timeZone: .gmt, firstWeekday: 1, minimumDaysInFirstWeek: 1, gregorianStartDate: nil) var dc_customCalendarNoTimeZone_customTimeZone = dc @@ -2470,7 +2470,7 @@ private struct GregorianCalendarInternationalizationTests { dc_customCalendarNoTimeZone_customTimeZone.timeZone = .init(secondsFromGMT: 28800) // calendar.timeZone = UTC+0, dc.calendar.timeZone = nil, dc.timeZone = UTC+8 // expect local time in dc.timeZone (UTC+8) - #expect(gregorianCalendar.date(from: dc_customCalendarNoTimeZone_customTimeZone)!.timeIntervalSinceReferenceDate == 679024975.891) // 2022-07-09T02:02:55Z + #expect(gregorianCalendar.date(from: dc_customCalendarNoTimeZone_customTimeZone)! == Date(timeIntervalSinceReferenceDate: 679024975.891)) // 2022-07-09T02:02:55Z } @Test func dateFromComponents_componentsTimeZoneConversion() {