Skip to content

Commit f16ab17

Browse files
committed
Add feature to force float64-representable durations
1 parent 71b78df commit f16ab17

3 files changed

Lines changed: 32 additions & 8 deletions

File tree

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ tzdb = [
109109
"timezone_provider/tzif",
110110
]
111111
std = []
112+
# https://github.com/boa-dev/temporal/issues/613
113+
# ECMA-conformant implementations must store durations as float64-representable numbers
114+
# Rust users probably should not enable this, unless they wish to match the quirks of JavaScript
115+
float64_representable_durations = []
112116

113117
[package.metadata.cargo-all-features]
114118
denylist = ["default"]

src/builtins/core/duration.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,21 @@ impl Duration {
389389
hours,
390390
minutes,
391391
seconds,
392+
393+
// https://github.com/boa-dev/temporal/issues/613
394+
// With float64_representable_durations enabled, force all smaller units
395+
// to be in the float64-representable range.
396+
#[cfg(feature = "float64_representable_durations")]
397+
milliseconds: milliseconds as f64 as u64,
398+
#[cfg(feature = "float64_representable_durations")]
399+
microseconds: microseconds as f64 as u128,
400+
#[cfg(feature = "float64_representable_durations")]
401+
nanoseconds: nanoseconds as f64 as u128,
402+
#[cfg(not(feature = "float64_representable_durations"))]
392403
milliseconds,
404+
#[cfg(not(feature = "float64_representable_durations"))]
393405
microseconds,
406+
#[cfg(not(feature = "float64_representable_durations"))]
394407
nanoseconds,
395408
}
396409
}

src/builtins/core/duration/tests.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -404,17 +404,11 @@ fn test_duration_compare() {
404404
)
405405
}
406406
}
407-
/*
408-
TODO: Uncomment
409407

410-
The below test should fail, but currently doesn't. This has to do with weird
411-
floating point math in IsValidDuration Step 6-8 that defers to C++ std::remquo
412-
413-
Needs further clarification.
408+
const MAX_SAFE_INT: i64 = 9_007_199_254_740_991;
414409

415410
#[test]
416411
fn duration_round_out_of_range_norm_conversion() {
417-
const MAX_SAFE_INT: i64 = 9_007_199_254_740_991;
418412
let duration = Duration::new(0, 0, 0, 0, 0, 0, MAX_SAFE_INT, 0, 0, 999_999_999).unwrap();
419413
let err = duration.round_with_provider( RoundingOptions {
420414
largest_unit: Some(Unit::Nanosecond),
@@ -423,4 +417,17 @@ fn duration_round_out_of_range_norm_conversion() {
423417
}, None, &NeverProvider::default());
424418
assert!(err.is_err())
425419
}
426-
*/
420+
421+
#[test]
422+
#[cfg_attr(not(feature = "float64_representable_durations"), should_panic)]
423+
fn duration_float64_representable() {
424+
// built-ins/Temporal/Duration/prototype/add/float64-representable-integer
425+
let duration = Duration::new(0, 0, 0, 0, 0, 0, 0, 0, MAX_SAFE_INT as i128, 0).unwrap();
426+
let duration2 = Duration::new(0, 0, 0, 0, 0, 0, 0, 0, MAX_SAFE_INT as i128 - 1, 0).unwrap();
427+
let added = duration.add(&duration2).unwrap();
428+
assert_eq!(added.microseconds, 18014398509481980);
429+
assert_eq!(added.as_temporal_string(Default::default()).unwrap(), "PT18014398509.48198S");
430+
let one_ms = Duration::new(0, 0, 0, 0, 0, 0, 0, 0, 1, 0).unwrap();
431+
let added_plus_one = added.add(&one_ms).unwrap();
432+
assert_eq!(added, added_plus_one, "Should not internally use a more accurate representation when adding");
433+
}

0 commit comments

Comments
 (0)