diff --git a/src/builtins/core/calendar.rs b/src/builtins/core/calendar.rs index d4b55eb74..97ac5a08e 100644 --- a/src/builtins/core/calendar.rs +++ b/src/builtins/core/calendar.rs @@ -514,12 +514,16 @@ impl Calendar { .days .try_into() .map_err(|_| TemporalError::range().with_enum(ErrorMessage::DurationNotValid))?; - let duration = DateDuration::new( + let mut duration = DateDuration::new( added.years.into(), added.months.into(), added.weeks.into(), days, )?; + + if added.is_negative { + duration = duration.negated(); + } Ok(Duration::from(duration)) } diff --git a/src/builtins/core/plain_date_time.rs b/src/builtins/core/plain_date_time.rs index 81715fe2b..92f0a8d03 100644 --- a/src/builtins/core/plain_date_time.rs +++ b/src/builtins/core/plain_date_time.rs @@ -1309,6 +1309,24 @@ mod tests { assert_eq!(result.minutes(), 30); } + #[test] + fn dt_since_conflicting_signs() { + // From intl402/Temporal/PlainDateTime/prototype/since/wrapping-at-end-of-month-gregorian + // Tests that date arithmetic with conflicting signs works + let a = PlainDateTime::try_new(2023, 3, 1, 2, 0, 0, 0, 0, 0, Calendar::GREGORIAN).unwrap(); + let b = PlainDateTime::try_new(2023, 1, 1, 3, 0, 0, 0, 0, 0, Calendar::GREGORIAN).unwrap(); + + let settings = DifferenceSettings { + largest_unit: Some(Unit::Year), + ..Default::default() + }; + let result = a.since(&b, settings).unwrap(); + + assert_eq!(result.months(), 1); + assert_eq!(result.days(), 30); + assert_eq!(result.hours(), 23); + } + #[test] fn dt_round_basic() { let assert_datetime =