diff --git a/src/builtins/core/duration.rs b/src/builtins/core/duration.rs index afc78cb90..aa59bda8f 100644 --- a/src/builtins/core/duration.rs +++ b/src/builtins/core/duration.rs @@ -181,27 +181,26 @@ impl Duration { duration_record.normalized_time_duration(), largest_unit, )?; - Self::new( - duration_record.date().years.into(), - duration_record.date().months.into(), - duration_record.date().weeks.into(), + let sign = duration_record.sign()?; + let mut duration = Self::new( + i64::from(duration_record.date().years), + i64::from(duration_record.date().months), + i64::from(duration_record.date().weeks), i64::try_from(duration_record.date().days) .or(Err(TemporalError::range()))? .checked_add(overflow_day) .ok_or(TemporalError::range())?, - time.hours.try_into().or(Err(TemporalError::range()))?, - time.minutes.try_into().or(Err(TemporalError::range()))?, - time.seconds.try_into().or(Err(TemporalError::range()))?, - time.milliseconds - .try_into() - .or(Err(TemporalError::range()))?, - time.microseconds - .try_into() - .or(Err(TemporalError::range()))?, - time.nanoseconds - .try_into() - .or(Err(TemporalError::range()))?, - ) + i64::try_from(time.hours).or(Err(TemporalError::range()))?, + i64::try_from(time.minutes).or(Err(TemporalError::range()))?, + i64::try_from(time.seconds).or(Err(TemporalError::range()))?, + i64::try_from(time.milliseconds).or(Err(TemporalError::range()))?, + i128::try_from(time.microseconds).or(Err(TemporalError::range()))?, + i128::try_from(time.nanoseconds).or(Err(TemporalError::range()))?, + )?; + if sign == Sign::Negative { + duration = duration.negated(); + } + Ok(duration) } /// Returns this `Duration` as a `NormalizedTimeDuration`. @@ -1519,19 +1518,27 @@ impl FromStr for Duration { (0, 0, 0, 0) }; - let sign = parse_record.sign as i64; + let sign = if parse_record.sign == ixdtf::parsers::records::Sign::Negative { + Sign::Negative + } else { + Sign::Positive + }; - Self::new( - years as i64 * sign, - months as i64 * sign, - weeks as i64 * sign, - days as i64 * sign, - hours as i64 * sign, - minutes as i64 * sign, - seconds as i64 * sign, - millis as i64 * sign, - micros as i128 * sign as i128, - nanos as i128 * sign as i128, - ) + let mut duration = Self::new( + years as i64, + months as i64, + weeks as i64, + days as i64, + hours as i64, + minutes as i64, + seconds as i64, + millis as i64, + micros as i128, + nanos as i128, + )?; + if sign == Sign::Negative { + duration = duration.negated(); + } + Ok(duration) } } diff --git a/src/iso.rs b/src/iso.rs index bf6014d3c..21dbe875b 100644 --- a/src/iso.rs +++ b/src/iso.rs @@ -169,12 +169,14 @@ impl IsoDateTime { let date = PlainDate::new_unchecked(self.date, calendar); // 5. Let dateDuration be ? CreateTemporalDuration(years, months, weeks, days + timeResult.[[Days]], 0, 0, 0, 0, 0, 0). + let sign = date_duration.sign.as_sign_multiplier(); let date_duration = DateDuration::new( - date_duration.years.into(), - date_duration.months.into(), - date_duration.weeks.into(), + i64::from(date_duration.years) * i64::from(sign), + i64::from(date_duration.months) * i64::from(sign), + i64::from(date_duration.weeks) * i64::from(sign), i64::try_from(date_duration.days) .or(Err(TemporalError::range()))? + * i64::from(sign) .checked_add(t_result.0) .ok_or(TemporalError::range())?, )?; @@ -399,9 +401,13 @@ impl IsoDate { // 1. Assert: year, month, day, years, months, weeks, and days are integers. // 2. Assert: overflow is either "constrain" or "reject". // 3. Let intermediate be ! BalanceISOYearMonth(year + years, month + months). + let year_offset = i64::from(duration.years) + * i64::from(duration.sign.as_sign_multiplier()); + let month_offset = i64::from(duration.months) + * i64::from(duration.sign.as_sign_multiplier()); let intermediate = balance_iso_year_month_with_clamp( - i64::from(self.year) + i64::from(duration.years), - i64::from(self.month) + i64::from(duration.months), + i64::from(self.year) + year_offset, + i64::from(self.month) + month_offset, ); // 4. Let intermediate be ? RegulateISODate(intermediate.[[Year]], intermediate.[[Month]], day, overflow). @@ -410,7 +416,9 @@ impl IsoDate { // 5. Set days to days + 7 × weeks. let additional_days = i64::try_from(duration.days).or(Err(TemporalError::range()))? - + (7 * i64::from(duration.weeks)); // Verify + * i64::from(duration.sign.as_sign_multiplier()) + + (7 * i64::from(duration.weeks) + * i64::from(duration.sign.as_sign_multiplier())); // 6. Let d be intermediate.[[Day]] + days. let intermediate_days = i64::from(intermediate.day) + additional_days; diff --git a/src/lib.rs b/src/lib.rs index 1bc372696..f2f6e21ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -259,10 +259,11 @@ impl From for Sign { impl Sign { /// Coerces the current `Sign` to be either negative or positive. pub(crate) fn as_sign_multiplier(&self) -> i8 { - if matches!(self, Self::Zero) { - return 1; + match self { + Self::Positive => 1, + Self::Negative => -1, + Self::Zero => 0, } - *self as i8 } pub(crate) fn negate(&self) -> Sign {