Skip to content

Commit 8aee6d1

Browse files
committed
initial implementation of duration.prototype.total
1 parent a6b3223 commit 8aee6d1

File tree

1 file changed

+222
-2
lines changed

1 file changed

+222
-2
lines changed

src/builtins/core/duration/normalized.rs

Lines changed: 222 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,18 @@ struct NudgeRecord {
303303
expanded: bool,
304304
}
305305

306+
// TODO: Review question:
307+
// had to create a new nudgerecord that doesn't convert and store to i128 in nudge_calendar_unit(),
308+
// as well as a duplicate function to nudge_calendar_unit_f64() to make it work :/
309+
// Any suggestions on how to make it better?
310+
#[allow(dead_code)]
311+
struct NudgeRecordF64 {
312+
normalized: NormalizedDurationRecord,
313+
_total: Option<f64>, // Adjusted to f64
314+
nudge_epoch_ns: i128,
315+
expanded: bool,
316+
}
317+
306318
impl NormalizedDurationRecord {
307319
// TODO: Add assertion into impl.
308320
// TODO: Add unit tests specifically for nudge_calendar_unit if possible.
@@ -595,6 +607,214 @@ impl NormalizedDurationRecord {
595607
}
596608
}
597609

610+
fn nudge_calendar_unit_f64(
611+
&self,
612+
sign: Sign,
613+
dest_epoch_ns: i128,
614+
dt: &PlainDateTime,
615+
tz: Option<(&TimeZone, &impl TimeZoneProvider)>,
616+
options: ResolvedRoundingOptions,
617+
) -> TemporalResult<NudgeRecordF64> {
618+
let (r1, r2, start_duration, end_duration) = match options.smallest_unit {
619+
TemporalUnit::Year => {
620+
let years = IncrementRounder::from_signed_num(
621+
self.date().years.0,
622+
options.increment.as_extended_increment(),
623+
)?
624+
.round(TemporalRoundingMode::Trunc);
625+
let r1 = years;
626+
let r2 = years
627+
+ i128::from(options.increment.get()) * i128::from(sign.as_sign_multiplier());
628+
(
629+
r1,
630+
r2,
631+
DateDuration::new(
632+
FiniteF64::try_from(r1)?,
633+
FiniteF64::default(),
634+
FiniteF64::default(),
635+
FiniteF64::default(),
636+
)?,
637+
DateDuration::new(
638+
FiniteF64::try_from(r2)?,
639+
FiniteF64::default(),
640+
FiniteF64::default(),
641+
FiniteF64::default(),
642+
)?,
643+
)
644+
}
645+
TemporalUnit::Month => {
646+
let months = IncrementRounder::from_signed_num(
647+
self.date().months.0,
648+
options.increment.as_extended_increment(),
649+
)?
650+
.round(TemporalRoundingMode::Trunc);
651+
let r1 = months;
652+
let r2 = months
653+
+ i128::from(options.increment.get()) * i128::from(sign.as_sign_multiplier());
654+
(
655+
r1,
656+
r2,
657+
DateDuration::new(
658+
self.date().years,
659+
FiniteF64::try_from(r1)?,
660+
FiniteF64::default(),
661+
FiniteF64::default(),
662+
)?,
663+
DateDuration::new(
664+
self.date().years,
665+
FiniteF64::try_from(r2)?,
666+
FiniteF64::default(),
667+
FiniteF64::default(),
668+
)?,
669+
)
670+
}
671+
TemporalUnit::Week => {
672+
let iso_one = IsoDate::balance(
673+
dt.iso_year() + self.date().years.as_date_value()?,
674+
i32::from(dt.iso_month()) + self.date().months.as_date_value()?,
675+
i32::from(dt.iso_day()),
676+
);
677+
678+
let iso_two = IsoDate::balance(
679+
dt.iso_year() + self.date().years.as_date_value()?,
680+
i32::from(dt.iso_month()) + self.date().months.as_date_value()?,
681+
i32::from(dt.iso_day()) + self.date().days.as_date_value()?,
682+
);
683+
684+
let weeks_start = PlainDate::try_new(
685+
iso_one.year,
686+
iso_one.month,
687+
iso_one.day,
688+
dt.calendar().clone(),
689+
)?;
690+
691+
let weeks_end = PlainDate::try_new(
692+
iso_two.year,
693+
iso_two.month,
694+
iso_two.day,
695+
dt.calendar().clone(),
696+
)?;
697+
698+
let until_result =
699+
weeks_start.internal_diff_date(&weeks_end, TemporalUnit::Week)?;
700+
701+
let weeks = IncrementRounder::from_signed_num(
702+
self.date().weeks.checked_add(&until_result.weeks())?.0,
703+
options.increment.as_extended_increment(),
704+
)?
705+
.round(TemporalRoundingMode::Trunc);
706+
707+
let r1 = weeks;
708+
let r2 = weeks
709+
+ i128::from(options.increment.get()) * i128::from(sign.as_sign_multiplier());
710+
(
711+
r1,
712+
r2,
713+
DateDuration::new(
714+
self.date().years,
715+
self.date().months,
716+
FiniteF64::try_from(r1)?,
717+
FiniteF64::default(),
718+
)?,
719+
DateDuration::new(
720+
self.date().years,
721+
self.date().months,
722+
FiniteF64::try_from(r2)?,
723+
FiniteF64::default(),
724+
)?,
725+
)
726+
}
727+
TemporalUnit::Day => {
728+
let days = IncrementRounder::from_signed_num(
729+
self.date().days.0,
730+
options.increment.as_extended_increment(),
731+
)?
732+
.round(TemporalRoundingMode::Trunc);
733+
let r1 = days;
734+
let r2 = days
735+
+ i128::from(options.increment.get()) * i128::from(sign.as_sign_multiplier());
736+
(
737+
r1,
738+
r2,
739+
DateDuration::new(
740+
self.date().years,
741+
self.date().months,
742+
self.date().weeks,
743+
FiniteF64::try_from(r1)?,
744+
)?,
745+
DateDuration::new(
746+
self.date().years,
747+
self.date().months,
748+
self.date().weeks,
749+
FiniteF64::try_from(r2)?,
750+
)?,
751+
)
752+
}
753+
_ => unreachable!(),
754+
};
755+
756+
let start = dt.iso.add_date_duration(
757+
dt.calendar().clone(),
758+
&start_duration,
759+
NormalizedTimeDuration::default(),
760+
None,
761+
)?;
762+
763+
let end = dt.iso.add_date_duration(
764+
dt.calendar().clone(),
765+
&end_duration,
766+
NormalizedTimeDuration::default(),
767+
None,
768+
)?;
769+
770+
let (start_epoch_ns, end_epoch_ns) = if let Some((tz, provider)) = tz {
771+
let start_epoch_ns =
772+
tz.get_epoch_nanoseconds_for(start, Disambiguation::Compatible, provider)?;
773+
let end_epoch_ns =
774+
tz.get_epoch_nanoseconds_for(end, Disambiguation::Compatible, provider)?;
775+
(start_epoch_ns, end_epoch_ns)
776+
} else {
777+
(start.as_nanoseconds()?, end.as_nanoseconds()?)
778+
};
779+
780+
if end_epoch_ns == start_epoch_ns {
781+
return Err(
782+
TemporalError::range().with_message("endEpochNs cannot be equal to startEpochNs")
783+
);
784+
}
785+
786+
let progress =
787+
(dest_epoch_ns - start_epoch_ns.0) as f64 / (end_epoch_ns.0 - start_epoch_ns.0) as f64;
788+
let total = r1 as f64
789+
+ progress * options.increment.get() as f64 * f64::from(sign.as_sign_multiplier());
790+
791+
let rounded_unit =
792+
IncrementRounder::from_signed_num(total, options.increment.as_extended_increment())?
793+
.round(options.rounding_mode);
794+
795+
if rounded_unit == r2 {
796+
Ok(NudgeRecordF64 {
797+
normalized: NormalizedDurationRecord::new(
798+
end_duration,
799+
NormalizedTimeDuration::default(),
800+
)?,
801+
_total: Some(total),
802+
nudge_epoch_ns: end_epoch_ns.0,
803+
expanded: true,
804+
})
805+
} else {
806+
Ok(NudgeRecordF64 {
807+
normalized: NormalizedDurationRecord::new(
808+
start_duration,
809+
NormalizedTimeDuration::default(),
810+
)?,
811+
_total: Some(total),
812+
nudge_epoch_ns: start_epoch_ns.0,
813+
expanded: false,
814+
})
815+
}
816+
}
817+
598818
// TODO: Clean up
599819
#[inline]
600820
fn nudge_to_zoned_time(
@@ -969,7 +1189,7 @@ impl NormalizedDurationRecord {
9691189
// a. Let sign be InternalDurationSign(duration).
9701190
let sign = self.sign()?;
9711191
// b. Let record be ? NudgeToCalendarUnit(sign, duration, destEpochNs, isoDateTime, timeZone, calendar, 1, unit, trunc).
972-
let record = self.nudge_calendar_unit(
1192+
let record = self.nudge_calendar_unit_f64(
9731193
sign,
9741194
dest_epoch_ns,
9751195
dt,
@@ -983,7 +1203,7 @@ impl NormalizedDurationRecord {
9831203
)?;
9841204

9851205
// c. Return record.[[Total]].
986-
return Ok(record._total.map(|t| t as f64).unwrap_or(0.0));
1206+
return record._total.temporal_unwrap();
9871207
}
9881208
// 2. Let timeDuration be ! Add24HourDaysToTimeDuration(duration.[[Time]], duration.[[Date]].[[Days]]).
9891209
let time_duration = self

0 commit comments

Comments
 (0)