@@ -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+
306318impl 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