Skip to content

Commit df7f16e

Browse files
committed
Address a couple bugs
1 parent f455fbd commit df7f16e

2 files changed

Lines changed: 62 additions & 10 deletions

File tree

src/builtins/core/duration.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
parsers::{FormattableDateDuration, FormattableDuration, FormattableTimeDuration, Precision},
1111
primitive::FiniteF64,
1212
provider::TimeZoneProvider,
13-
temporal_assert, Sign, TemporalError, TemporalResult, TemporalUnwrap,
13+
temporal_assert, Sign, TemporalError, TemporalResult, TemporalUnwrap, NS_PER_DAY,
1414
};
1515
use alloc::format;
1616
use alloc::string::String;
@@ -658,7 +658,6 @@ impl Duration {
658658
let internal = NormalizedDurationRecord::from_duration_with_24_hour_days(self)?;
659659
// 31. If smallestUnit is day, then
660660
let internal = if resolved_options.smallest_unit == Unit::Day {
661-
// TODO: TEST
662661
// a. Let fractionalDays be TotalTimeDuration(internalDuration.[[Time]], day).
663662
// b. Let days be RoundNumberToIncrement(fractionalDays, roundingIncrement, roundingMode).
664663
let days = internal
@@ -670,7 +669,7 @@ impl Duration {
670669
// c. Let dateDuration be ? CreateDateDurationRecord(0, 0, 0, days).
671670
let date = DateDuration::new(0, 0, 0, days)?;
672671
// d. Set internalDuration to CombineDateAndTimeDuration(dateDuration, 0).
673-
NormalizedDurationRecord::new(date, norm)?
672+
NormalizedDurationRecord::new(date, NormalizedTimeDuration::default())?
674673
// 32. Else,
675674
} else {
676675
// TODO: update round / round_inner methods
@@ -769,8 +768,9 @@ impl Duration {
769768
return Err(TemporalError::range());
770769
}
771770
// c. Let internalDuration be ToInternalDurationRecordWith24HourDays(duration).
771+
let internal = NormalizedDurationRecord::from_duration_with_24_hour_days(self)?;
772772
// d. Let total be TotalTimeDuration(internalDuration.[[Time]], unit).
773-
let total = self.time.to_normalized().total(unit)?;
773+
let total = internal.normalized_time_duration().total(unit)?;
774774
Ok(total)
775775
}
776776
}
@@ -867,6 +867,7 @@ pub fn duration_to_formattable(
867867
// TODO: Update, optimize, and fix the below. is_valid_duration should probably be generic over a T.
868868

869869
const TWO_POWER_FIFTY_THREE: i128 = 9_007_199_254_740_992;
870+
const MAX_SAFE_NS_PRECISION: i128 = TWO_POWER_FIFTY_THREE * 1_000_000_000;
870871

871872
// NOTE: Can FiniteF64 optimize the duration_validation
872873
/// Utility function to check whether the `Duration` fields are valid.
@@ -933,15 +934,16 @@ pub(crate) fn is_valid_duration(
933934
// in C++ with an implementation of core::remquo() with sufficient bits in the quotient.
934935
// String manipulation will also give an exact result, since the multiplication is by a power of 10.
935936
// Seconds part
936-
let normalized_seconds =
937-
(days as i128 * 86_400) + (hours as i128) * 3600 + minutes as i128 * 60 + seconds as i128;
937+
// TODO: Fix the below parts after clarification around behavior.
938+
let normalized_nanoseconds =
939+
(days as i128 * NS_PER_DAY as i128) + (hours as i128) * 3_600_000_000_000 + minutes as i128 * 60_000_000_000 + seconds as i128 * 1_000_000_000;
938940
// Subseconds part
939941
let normalized_subseconds_parts =
940-
(milliseconds as i128 / 1_000) + (microseconds / 1_000_000) + (nanoseconds / 1_000_000_000);
942+
(milliseconds as i128 * 1_000_000) + (microseconds * 1_000) + nanoseconds;
941943

942-
let normalized_seconds = normalized_seconds + normalized_subseconds_parts;
944+
let normalized_seconds = normalized_nanoseconds + normalized_subseconds_parts;
943945
// 8. If abs(normalizedSeconds) ≥ 2**53, return false.
944-
if normalized_seconds.abs() >= TWO_POWER_FIFTY_THREE {
946+
if normalized_seconds.abs() >= MAX_SAFE_NS_PRECISION {
945947
return false;
946948
}
947949

src/builtins/core/duration/tests.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use core::str::FromStr;
22

3-
use crate::{options::ToStringRoundingOptions, parsers::Precision, partial::PartialDuration};
3+
use crate::{options::{RoundingOptions, ToStringRoundingOptions, Unit}, parsers::Precision, partial::PartialDuration, provider::NeverProvider};
44

55
use super::Duration;
66

@@ -184,3 +184,53 @@ fn duration_from_str() {
184184
assert_eq!(duration.microseconds(), 999);
185185
assert_eq!(duration.nanoseconds(), 940);
186186
}
187+
188+
#[test]
189+
fn duration_max() {
190+
let cases = [
191+
(Duration::new(0, 0, 0, 104249991374, 7, 36, 31, 999, 999, 999).unwrap(), "max days", 9007199254740991.999999999),
192+
(Duration::new(0, 0, 0, 0, 2501999792983, 36, 31, 999, 999, 999).unwrap(), "max hours", 9007199254740991.999999999),
193+
(Duration::new(0, 0, 0, 0, 0, 150119987579016, 31, 999, 999, 999).unwrap(), "max minutes", 9007199254740991.999999999),
194+
(Duration::new(0, 0, 0, 0, 0, 0, 9007199254740991, 999, 999, 999).unwrap(), "max seconds", 9007199254740991.999999999),
195+
(Duration::new(0, 0, 0, -104249991374, -7, -36, -31, -999, -999, -999).unwrap(), "min days", -9007199254740991.999999999),
196+
(Duration::new(0, 0, 0, 0, -2501999792983, -36, -31, -999, -999, -999).unwrap(), "min hours", -9007199254740991.999999999),
197+
(Duration::new(0, 0, 0, 0, 0, -150119987579016, -31, -999, -999, -999).unwrap(), "min minutes", -9007199254740991.999999999),
198+
(Duration::new(0, 0, 0, 0, 0, 0, -9007199254740991, -999, -999, -999).unwrap(), "min seconds", -9007199254740991.999999999),
199+
];
200+
201+
for (duration, description, result) in cases {
202+
assert_eq!(duration.total_with_provider(Unit::Second, None, &NeverProvider).unwrap().0, result, "{description}");
203+
}
204+
}
205+
206+
#[test]
207+
fn duration_round_negative() {
208+
let duration = Duration::new(0, 0, 0, 0, -60, 0, 0, 0, 0, 0).unwrap();
209+
let result = duration.round_with_provider(RoundingOptions {
210+
smallest_unit: Some(Unit::Day),
211+
..Default::default()
212+
}, None, &NeverProvider).unwrap();
213+
assert_eq!(result.days(), -3);
214+
215+
}
216+
217+
/*
218+
TODO: Uncomment
219+
220+
The below test should fail, but currently doesn't. This has to do with weird
221+
floating point math in IsValidDuration Step 6-8 that defers to C++ std::remquo
222+
223+
Needs further clarification.
224+
225+
#[test]
226+
fn duration_round_out_of_range_norm_conversion() {
227+
const MAX_SAFE_INT: i64 = 9_007_199_254_740_991;
228+
let duration = Duration::new(0, 0, 0, 0, 0, 0, MAX_SAFE_INT, 0, 0, 999_999_999).unwrap();
229+
let err = duration.round_with_provider( RoundingOptions {
230+
largest_unit: Some(Unit::Nanosecond),
231+
increment: Some(RoundingIncrement::ONE),
232+
..Default::default()
233+
}, None, &NeverProvider);
234+
assert!(err.is_err())
235+
}
236+
*/

0 commit comments

Comments
 (0)