@@ -19,6 +19,7 @@ pub struct Time {
19
19
impl Time {
20
20
#[ inline]
21
21
#[ must_use]
22
+ /// Creates a new unvalidated `Time`.
22
23
pub ( crate ) fn new_unchecked ( iso : IsoTime ) -> Self {
23
24
Self { iso }
24
25
}
@@ -46,6 +47,69 @@ impl Time {
46
47
47
48
Self :: new_unchecked ( result)
48
49
}
50
+
51
+ /// Performs a desired difference op between two `Time`'s, returning the resulting `Duration`.
52
+ pub ( crate ) fn diff_time (
53
+ & self ,
54
+ op : bool ,
55
+ other : & Time ,
56
+ rounding_mode : Option < TemporalRoundingMode > ,
57
+ rounding_increment : Option < f64 > ,
58
+ largest_unit : Option < TemporalUnit > ,
59
+ smallest_unit : Option < TemporalUnit > ,
60
+ ) -> TemporalResult < Duration > {
61
+ // 1. If operation is SINCE, let sign be -1. Otherwise, let sign be 1.
62
+ // 2. Set other to ? ToTemporalTime(other).
63
+ // 3. Let resolvedOptions be ? SnapshotOwnProperties(? GetOptionsObject(options), null).
64
+ // 4. Let settings be ? GetDifferenceSettings(operation, resolvedOptions, TIME, « », "nanosecond", "hour").
65
+ let increment = utils:: to_rounding_increment ( rounding_increment) ?;
66
+ let ( sign, rounding_mode) = if op {
67
+ (
68
+ -1.0 ,
69
+ rounding_mode
70
+ . unwrap_or ( TemporalRoundingMode :: Trunc )
71
+ . negate ( ) ,
72
+ )
73
+ } else {
74
+ ( 1.0 , rounding_mode. unwrap_or ( TemporalRoundingMode :: Trunc ) )
75
+ } ;
76
+
77
+ let smallest_unit = smallest_unit. unwrap_or ( TemporalUnit :: Nanosecond ) ;
78
+ // Use the defaultlargestunit which is max smallestlargestdefault and smallestunit
79
+ let largest_unit = largest_unit. unwrap_or ( smallest_unit. max ( TemporalUnit :: Hour ) ) ;
80
+
81
+ // 5. Let norm be ! DifferenceTime(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]],
82
+ // temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]],
83
+ // temporalTime.[[ISONanosecond]], other.[[ISOHour]], other.[[ISOMinute]], other.[[ISOSecond]],
84
+ // other.[[ISOMillisecond]], other.[[ISOMicrosecond]], other.[[ISONanosecond]]).
85
+ let time = self . iso . diff ( & other. iso ) ;
86
+
87
+ // 6. If settings.[[SmallestUnit]] is not "nanosecond" or settings.[[RoundingIncrement]] ≠ 1, then
88
+ let norm = if smallest_unit != TemporalUnit :: Nanosecond || rounding_increment != Some ( 1.0 ) {
89
+ // a. Let roundRecord be ! RoundDuration(0, 0, 0, 0, norm, settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
90
+ let round_record = time. round ( increment, smallest_unit, rounding_mode) ?;
91
+ // b. Set norm to roundRecord.[[NormalizedDuration]].[[NormalizedTime]].
92
+ round_record. 0
93
+ } else {
94
+ time. to_normalized ( )
95
+ } ;
96
+
97
+ // 7. Let result be BalanceTimeDuration(norm, settings.[[LargestUnit]]).
98
+ let result = TimeDuration :: from_normalized ( norm, largest_unit) ?. 1 ;
99
+ // 8. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]).
100
+ Duration :: new (
101
+ 0.0 ,
102
+ 0.0 ,
103
+ 0.0 ,
104
+ 0.0 ,
105
+ sign * result. hours ,
106
+ sign * result. minutes ,
107
+ sign * result. seconds ,
108
+ sign * result. milliseconds ,
109
+ sign * result. microseconds ,
110
+ sign * result. nanoseconds ,
111
+ )
112
+ }
49
113
}
50
114
51
115
// ==== Public API ====
@@ -147,6 +211,50 @@ impl Time {
147
211
self . add_to_time ( & duration. negated ( ) )
148
212
}
149
213
214
+ #[ inline]
215
+ /// Returns the `Duration` until the provided `Time` from the current `Time`.
216
+ ///
217
+ /// NOTE: `until` assumes the provided other time will occur in the future relative to the current.
218
+ pub fn until (
219
+ & self ,
220
+ other : & Self ,
221
+ rounding_mode : Option < TemporalRoundingMode > ,
222
+ rounding_increment : Option < f64 > ,
223
+ largest_unit : Option < TemporalUnit > ,
224
+ smallest_unit : Option < TemporalUnit > ,
225
+ ) -> TemporalResult < Duration > {
226
+ self . diff_time (
227
+ false ,
228
+ other,
229
+ rounding_mode,
230
+ rounding_increment,
231
+ largest_unit,
232
+ smallest_unit,
233
+ )
234
+ }
235
+
236
+ #[ inline]
237
+ /// Returns the `Duration` since the provided `Time` from the current `Time`.
238
+ ///
239
+ /// NOTE: `since` assumes the provided other time is in the past relative to the current.
240
+ pub fn since (
241
+ & self ,
242
+ other : & Self ,
243
+ rounding_mode : Option < TemporalRoundingMode > ,
244
+ rounding_increment : Option < f64 > ,
245
+ largest_unit : Option < TemporalUnit > ,
246
+ smallest_unit : Option < TemporalUnit > ,
247
+ ) -> TemporalResult < Duration > {
248
+ self . diff_time (
249
+ true ,
250
+ other,
251
+ rounding_mode,
252
+ rounding_increment,
253
+ largest_unit,
254
+ smallest_unit,
255
+ )
256
+ }
257
+
150
258
// TODO (nekevss): optimize and test rounding_increment type (f64 vs. u64).
151
259
/// Rounds the current `Time` according to provided options.
152
260
pub fn round (
@@ -177,17 +285,28 @@ impl Time {
177
285
178
286
#[ cfg( test) ]
179
287
mod tests {
180
- use crate :: { components:: Duration , iso:: IsoTime , options:: TemporalUnit } ;
288
+ use crate :: {
289
+ components:: Duration ,
290
+ iso:: IsoTime ,
291
+ options:: { ArithmeticOverflow , TemporalUnit } ,
292
+ } ;
181
293
182
294
use super :: Time ;
183
295
184
296
fn assert_time ( result : Time , values : ( u8 , u8 , u8 , u16 , u16 , u16 ) ) {
185
- assert ! ( result. hour( ) == values. 0 ) ;
186
- assert ! ( result. minute( ) == values. 1 ) ;
187
- assert ! ( result. second( ) == values. 2 ) ;
188
- assert ! ( result. millisecond( ) == values. 3 ) ;
189
- assert ! ( result. microsecond( ) == values. 4 ) ;
190
- assert ! ( result. nanosecond( ) == values. 5 ) ;
297
+ assert_eq ! (
298
+ result,
299
+ Time {
300
+ iso: IsoTime {
301
+ hour: values. 0 ,
302
+ minute: values. 1 ,
303
+ second: values. 2 ,
304
+ millisecond: values. 3 ,
305
+ microsecond: values. 4 ,
306
+ nanosecond: values. 5 ,
307
+ }
308
+ }
309
+ ) ;
191
310
}
192
311
193
312
#[ test]
@@ -272,4 +391,46 @@ mod tests {
272
391
273
392
assert_time ( result, ( 7 , 23 , 30 , 123 , 456 , 789 ) ) ;
274
393
}
394
+
395
+ #[ test]
396
+ fn since_basic ( ) {
397
+ let one = Time :: new ( 15 , 23 , 30 , 123 , 456 , 789 , ArithmeticOverflow :: Constrain ) . unwrap ( ) ;
398
+ let two = Time :: new ( 14 , 23 , 30 , 123 , 456 , 789 , ArithmeticOverflow :: Constrain ) . unwrap ( ) ;
399
+ let three = Time :: new ( 13 , 30 , 30 , 123 , 456 , 789 , ArithmeticOverflow :: Constrain ) . unwrap ( ) ;
400
+
401
+ let result = one. since ( & two, None , None , None , None ) . unwrap ( ) ;
402
+ assert_eq ! ( result. hours( ) , 1.0 ) ;
403
+
404
+ let result = two. since ( & one, None , None , None , None ) . unwrap ( ) ;
405
+ assert_eq ! ( result. hours( ) , -1.0 ) ;
406
+
407
+ let result = one. since ( & three, None , None , None , None ) . unwrap ( ) ;
408
+ assert_eq ! ( result. hours( ) , 1.0 ) ;
409
+ assert_eq ! ( result. minutes( ) , 53.0 ) ;
410
+
411
+ let result = three. since ( & one, None , None , None , None ) . unwrap ( ) ;
412
+ assert_eq ! ( result. hours( ) , -1.0 ) ;
413
+ assert_eq ! ( result. minutes( ) , -53.0 ) ;
414
+ }
415
+
416
+ #[ test]
417
+ fn until_basic ( ) {
418
+ let one = Time :: new ( 15 , 23 , 30 , 123 , 456 , 789 , ArithmeticOverflow :: Constrain ) . unwrap ( ) ;
419
+ let two = Time :: new ( 16 , 23 , 30 , 123 , 456 , 789 , ArithmeticOverflow :: Constrain ) . unwrap ( ) ;
420
+ let three = Time :: new ( 17 , 0 , 30 , 123 , 456 , 789 , ArithmeticOverflow :: Constrain ) . unwrap ( ) ;
421
+
422
+ let result = one. until ( & two, None , None , None , None ) . unwrap ( ) ;
423
+ assert_eq ! ( result. hours( ) , 1.0 ) ;
424
+
425
+ let result = two. until ( & one, None , None , None , None ) . unwrap ( ) ;
426
+ assert_eq ! ( result. hours( ) , -1.0 ) ;
427
+
428
+ let result = one. until ( & three, None , None , None , None ) . unwrap ( ) ;
429
+ assert_eq ! ( result. hours( ) , 1.0 ) ;
430
+ assert_eq ! ( result. minutes( ) , 37.0 ) ;
431
+
432
+ let result = three. until ( & one, None , None , None , None ) . unwrap ( ) ;
433
+ assert_eq ! ( result. hours( ) , -1.0 ) ;
434
+ assert_eq ! ( result. minutes( ) , -37.0 ) ;
435
+ }
275
436
}
0 commit comments