@@ -114,6 +114,23 @@ extension Duration {
114114 return Duration ( _attoseconds:
115115 _Int128 ( seconds) . multiplied ( by: 1_000_000_000_000_000_000 as UInt64 ) )
116116 }
117+
118+ /// Construct a `Duration` given a duration and scale, taking care so that
119+ /// exact integer durations are preserved exactly.
120+ internal init ( _ duration: Double , scale: UInt64 ) {
121+ // Split the duration into integral and fractional parts, as we need to
122+ // handle them slightly differently to ensure that integer values are
123+ // never rounded if `scale` is representable as Double.
124+ let integralPart = duration. rounded ( . towardZero)
125+ let fractionalPart = integralPart - duration
126+ self . init ( _attoseconds:
127+ // This term may trap due to overflow, but it cannot round, so if the
128+ // input `seconds` is an exact integer, we get an exact integer result.
129+ _Int128 ( integralPart) . multiplied ( by: scale) +
130+ // This term may round, but cannot overflow.
131+ _Int128( ( fractionalPart * Double( scale) ) . rounded ( ) )
132+ )
133+ }
117134
118135 /// Construct a `Duration` given a number of seconds represented as a
119136 /// `Double` by converting the value into the closest attosecond scale value.
@@ -123,7 +140,7 @@ extension Duration {
123140 /// - Returns: A `Duration` representing a given number of seconds.
124141 @available ( SwiftStdlib 5 . 7 , * )
125142 public static func seconds( _ seconds: Double ) -> Duration {
126- return Duration ( _attoseconds : _Int128 ( seconds * 1_000_000_000_000_000_000 ) )
143+ Duration ( seconds, scale : 1_000_000_000_000_000_000 )
127144 }
128145
129146 /// Construct a `Duration` given a number of milliseconds represented as a
@@ -148,8 +165,7 @@ extension Duration {
148165 /// - Returns: A `Duration` representing a given number of milliseconds.
149166 @available ( SwiftStdlib 5 . 7 , * )
150167 public static func milliseconds( _ milliseconds: Double ) -> Duration {
151- return Duration ( _attoseconds:
152- _Int128 ( milliseconds * 1_000_000_000_000_000 ) )
168+ Duration ( milliseconds, scale: 1_000_000_000_000_000 )
153169 }
154170
155171 /// Construct a `Duration` given a number of microseconds represented as a
@@ -174,8 +190,7 @@ extension Duration {
174190 /// - Returns: A `Duration` representing a given number of microseconds.
175191 @available ( SwiftStdlib 5 . 7 , * )
176192 public static func microseconds( _ microseconds: Double ) -> Duration {
177- return Duration ( _attoseconds:
178- _Int128 ( microseconds * 1_000_000_000_000 ) )
193+ Duration ( microseconds, scale: 1_000_000_000_000 )
179194 }
180195
181196 /// Construct a `Duration` given a number of nanoseconds represented as a
0 commit comments