@@ -114,6 +114,23 @@ extension Duration {
114
114
return Duration ( _attoseconds:
115
115
_Int128 ( seconds) . multiplied ( by: 1_000_000_000_000_000_000 as UInt64 ) )
116
116
}
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
+ }
117
134
118
135
/// Construct a `Duration` given a number of seconds represented as a
119
136
/// `Double` by converting the value into the closest attosecond scale value.
@@ -123,7 +140,7 @@ extension Duration {
123
140
/// - Returns: A `Duration` representing a given number of seconds.
124
141
@available ( SwiftStdlib 5 . 7 , * )
125
142
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 )
127
144
}
128
145
129
146
/// Construct a `Duration` given a number of milliseconds represented as a
@@ -148,8 +165,7 @@ extension Duration {
148
165
/// - Returns: A `Duration` representing a given number of milliseconds.
149
166
@available ( SwiftStdlib 5 . 7 , * )
150
167
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 )
153
169
}
154
170
155
171
/// Construct a `Duration` given a number of microseconds represented as a
@@ -174,8 +190,7 @@ extension Duration {
174
190
/// - Returns: A `Duration` representing a given number of microseconds.
175
191
@available ( SwiftStdlib 5 . 7 , * )
176
192
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 )
179
194
}
180
195
181
196
/// Construct a `Duration` given a number of nanoseconds represented as a
0 commit comments