diff --git a/src/builtins/core/duration/normalized.rs b/src/builtins/core/duration/normalized.rs index 60c366aec..9def7f7e0 100644 --- a/src/builtins/core/duration/normalized.rs +++ b/src/builtins/core/duration/normalized.rs @@ -707,7 +707,7 @@ impl InternalDurationRecord { || (sign == NonZeroSign::Negative && r1 <= 0 && r1 > r2) ); - let start_epoch_ns = if r1 == 0 { + let start_epoch_ns = if start_duration.sign() == Sign::Zero { origin_epoch_ns } else { // 7. Let start be ? CalendarDateAdd(calendar, isoDateTime.[[ISODate]], startDuration, constrain). diff --git a/src/builtins/core/duration/tests.rs b/src/builtins/core/duration/tests.rs index 113d56802..2c1f448c5 100644 --- a/src/builtins/core/duration/tests.rs +++ b/src/builtins/core/duration/tests.rs @@ -605,3 +605,41 @@ fn out_of_bounds_duration_no_crash() { assert!(duration.is_err()); } + +// https://github.com/tc39/test262/commit/a70493eb104948583a7928d50eac28b6c81114bf +// https://github.com/tc39/proposal-temporal/issues/3316 +#[test] +#[cfg(feature = "compiled_data")] +fn test_exact_multiple_of_larger_unit_plaindate() { + use crate::options::RoundingMode; + use crate::PlainDate; + + let relative_to = PlainDate::try_new_iso(2012, 1, 1).unwrap(); + + // Temporal.Duration(0, 0, 0, 31).round({ smallestUnit: "weeks", largestUnit: "months", roundingMode, relativeTo }) + // should be 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 + let d1 = Duration::new(0, 0, 0, 31, 0, 0, 0, 0, 0, 0).unwrap(); + + for mode in [ + RoundingMode::Ceil, + RoundingMode::Floor, + RoundingMode::Expand, + RoundingMode::HalfCeil, + RoundingMode::HalfFloor, + RoundingMode::HalfEven, + RoundingMode::HalfExpand, + RoundingMode::HalfTrunc, + RoundingMode::Trunc, + ] { + let options = RoundingOptions { + smallest_unit: Some(Unit::Week), + largest_unit: Some(Unit::Month), + rounding_mode: Some(mode), + ..Default::default() + }; + let res = d1.round(options, Some(relative_to.clone().into())).unwrap(); + assert_eq!(res.months(), 1, "P31D weeks..months {mode:?}"); + assert_eq!(res.weeks(), 0, "P31D weeks..months {mode:?}"); + assert_eq!(res.days(), 0, "P31D weeks..months {mode:?}"); + } +} diff --git a/src/iso.rs b/src/iso.rs index 1771a7b34..833f141c7 100644 --- a/src/iso.rs +++ b/src/iso.rs @@ -452,7 +452,7 @@ impl IsoDate { // c. Repeat, while ISODateSurpasses(sign, intermediate.[[Year]], intermediate.[[Month]], d1, y2, m2, d2) is false, // Safety: balance_iso_year_month should always return a month value from 1..=12 while !iso_date_surpasses( - &IsoDate::new_unchecked(intermediate.0, intermediate.1 as u8, self.day), + &IsoDate::new_unchecked(intermediate.0, intermediate.1, self.day), other, sign, ) {