Skip to content

Commit 1562f63

Browse files
committed
Bump ixdtf to revision + Implement to_string methods for Duration, PlainYearMonth, and PlainMonthDay
1 parent 7bd7190 commit 1562f63

File tree

5 files changed

+82
-30
lines changed

5 files changed

+82
-30
lines changed

Cargo.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ icu_calendar = { version = "2.0.0-beta1", default-features = false}
2424
rustc-hash = "2.1.0"
2525
bitflags = "2.7.0"
2626
num-traits = "0.2.19"
27-
ixdtf = "0.3.0"
27+
ixdtf = { git = "https://github.com/unicode-org/icu4x.git", rev = "3d187da4d3f05b7e37603c4be3f2c1ce45100e03" }
2828
iana-time-zone = "0.1.61"
2929
log = "0.4.0"
3030
tzif = "0.3.0"

src/components/duration.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -687,13 +687,14 @@ pub fn duration_to_formattable(
687687
} else {
688688
IxdtfSign::Positive
689689
};
690+
let duration = duration.abs();
690691
let date = duration.years().0 + duration.months().0 + duration.weeks().0 + duration.days().0;
691692
let date = if date != 0.0 {
692693
Some(DateDurationRecord {
693694
years: duration.years().0 as u32,
694695
months: duration.months().0 as u32,
695696
weeks: duration.weeks().0 as u32,
696-
days: duration.days().0 as u32,
697+
days: duration.days().0 as u64,
697698
})
698699
} else {
699700
None
@@ -711,12 +712,12 @@ pub fn duration_to_formattable(
711712
duration.nanoseconds(),
712713
));
713714

714-
let seconds = time.seconds().unsigned_abs() as u32;
715+
let seconds = time.seconds().unsigned_abs() as u64;
715716
let subseconds = time.subseconds().unsigned_abs();
716717

717718
let time = Some(TimeDurationRecord::Seconds {
718-
hours: hours.0 as u32,
719-
minutes: minutes.0 as u32,
719+
hours: hours.0 as u64,
720+
minutes: minutes.0 as u64,
720721
seconds,
721722
fraction: subseconds,
722723
});
@@ -893,7 +894,7 @@ impl FromStr for Duration {
893894
let nanoseconds = rem.rem_euclid(1_000);
894895

895896
(
896-
f64::from(hours),
897+
hours as f64,
897898
minutes as f64,
898899
seconds as f64,
899900
milliseconds as f64,
@@ -917,8 +918,8 @@ impl FromStr for Duration {
917918
let nanoseconds = rem.rem_euclid(1_000);
918919

919920
(
920-
f64::from(hours),
921-
f64::from(minutes),
921+
hours as f64,
922+
minutes as f64,
922923
seconds as f64,
923924
milliseconds as f64,
924925
microseconds as f64,
@@ -939,9 +940,9 @@ impl FromStr for Duration {
939940
let nanoseconds = rem.rem_euclid(1_000);
940941

941942
(
942-
f64::from(hours),
943-
f64::from(minutes),
944-
f64::from(seconds),
943+
hours as f64,
944+
minutes as f64,
945+
seconds as f64,
945946
milliseconds as f64,
946947
microseconds as f64,
947948
nanoseconds as f64,
@@ -962,7 +963,7 @@ impl FromStr for Duration {
962963
FiniteF64::from(years).copysign(sign),
963964
FiniteF64::from(months).copysign(sign),
964965
FiniteF64::from(weeks).copysign(sign),
965-
FiniteF64::from(days).copysign(sign),
966+
FiniteF64::try_from(days)?.copysign(sign),
966967
FiniteF64::try_from(hours)?.copysign(sign),
967968
FiniteF64::try_from(minutes)?.copysign(sign),
968969
FiniteF64::try_from(seconds)?.copysign(sign),

src/components/duration/tests.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,3 +688,44 @@ fn default_duration_string() {
688688
let result = duration.to_temporal_string(options).unwrap();
689689
assert_eq!(&result, "PT0.000S");
690690
}
691+
692+
#[test]
693+
fn duration_to_string_auto_precision() {
694+
let duration = Duration::new(1.into(), 2.into(), 3.into(), 4.into(), 5.into(), 6.into(), 7.into(), FiniteF64::default(), FiniteF64::default(), FiniteF64::default()).unwrap();
695+
let result = duration.to_temporal_string(ToStringRoundingOptions::default()).unwrap();
696+
assert_eq!(&result, "P1Y2M3W4DT5H6M7S");
697+
698+
let duration = Duration::new(1.into(), 2.into(), 3.into(), 4.into(), 5.into(), 6.into(), 7.into(), 987.into(), 650.into(), FiniteF64::default()).unwrap();
699+
let result = duration.to_temporal_string(ToStringRoundingOptions::default()).unwrap();
700+
assert_eq!(&result, "P1Y2M3W4DT5H6M7.98765S");
701+
}
702+
703+
#[test]
704+
fn empty_date_duration() {
705+
let duration = Duration::from_partial_duration(PartialDuration {
706+
hours: Some(1.into()),
707+
..Default::default()
708+
}).unwrap();
709+
let result = duration.to_temporal_string(ToStringRoundingOptions::default()).unwrap();
710+
assert_eq!(&result, "PT1H");
711+
}
712+
713+
#[test]
714+
fn negative_fields_to_string() {
715+
let duration = Duration::from_partial_duration(PartialDuration {
716+
years: Some(FiniteF64::from(-1)),
717+
months: Some(FiniteF64::from(-1)),
718+
weeks: Some(FiniteF64::from(-1)),
719+
days: Some(FiniteF64::from(-1)),
720+
hours: Some(FiniteF64::from(-1)),
721+
minutes: Some(FiniteF64::from(-1)),
722+
seconds: Some(FiniteF64::from(-1)),
723+
milliseconds: Some(FiniteF64::from(-1)),
724+
microseconds: Some(FiniteF64::from(-1)),
725+
nanoseconds: Some(FiniteF64::from(-1)),
726+
}).unwrap();
727+
let result = duration.to_temporal_string(ToStringRoundingOptions::default()).unwrap();
728+
assert_eq!(&result, "-P1Y1M1W1DT1H1M1.001001001S");
729+
730+
731+
}

src/parsers.rs

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ impl Writeable for FormattableMonthDay<'_> {
377377
fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
378378
if self.calendar.show == DisplayCalendar::Always
379379
|| self.calendar.show == DisplayCalendar::Critical
380-
|| self.calendar.calendar == "iso8601"
380+
|| self.calendar.calendar != "iso8601"
381381
{
382382
write_year(self.date.0, sink)?;
383383
sink.write_char('-')?;
@@ -392,7 +392,7 @@ impl Writeable for FormattableMonthDay<'_> {
392392
let base_length = self.calendar.writeable_length_hint() + LengthHint::exact(5);
393393
if self.calendar.show == DisplayCalendar::Always
394394
|| self.calendar.show == DisplayCalendar::Critical
395-
|| self.calendar.calendar == "iso8601"
395+
|| self.calendar.calendar != "iso8601"
396396
{
397397
let year_length = if (0..=9999).contains(&self.date.0) {
398398
4
@@ -418,7 +418,7 @@ impl Writeable for FormattableYearMonth<'_> {
418418
write_padded_u8(self.date.1, sink)?;
419419
if self.calendar.show == DisplayCalendar::Always
420420
|| self.calendar.show == DisplayCalendar::Critical
421-
|| self.calendar.calendar == "iso8601"
421+
|| self.calendar.calendar != "iso8601"
422422
{
423423
sink.write_char('-')?;
424424
write_padded_u8(self.date.2, sink)?;
@@ -437,7 +437,7 @@ impl Writeable for FormattableYearMonth<'_> {
437437
self.calendar.writeable_length_hint() + LengthHint::exact(year_length + 3);
438438
if self.calendar.show == DisplayCalendar::Always
439439
|| self.calendar.show == DisplayCalendar::Critical
440-
|| self.calendar.calendar == "iso8601"
440+
|| self.calendar.calendar != "iso8601"
441441
{
442442
return base_length + LengthHint::exact(3);
443443
}
@@ -524,10 +524,10 @@ impl Writeable for FormattableDuration {
524524
}
525525
sink.write_char('P')?;
526526
if let Some(date) = self.duration.date {
527-
checked_write_with_suffix(date.years, 'Y', sink)?;
528-
checked_write_with_suffix(date.months, 'M', sink)?;
529-
checked_write_with_suffix(date.weeks, 'W', sink)?;
530-
checked_write_with_suffix(date.days, 'D', sink)?;
527+
checked_write_u32_with_suffix(date.years, 'Y', sink)?;
528+
checked_write_u32_with_suffix(date.months, 'M', sink)?;
529+
checked_write_u32_with_suffix(date.weeks, 'W', sink)?;
530+
checked_write_u64_with_suffix(date.days, 'D', sink)?;
531531
}
532532
if let Some(time) = self.duration.time {
533533
sink.write_char('T')?;
@@ -548,7 +548,7 @@ impl Writeable for FormattableDuration {
548548
minutes,
549549
fraction,
550550
} => {
551-
checked_write_with_suffix(hours, 'H', sink)?;
551+
checked_write_u64_with_suffix(hours, 'H', sink)?;
552552
if minutes == 0 {
553553
return Ok(());
554554
}
@@ -565,18 +565,17 @@ impl Writeable for FormattableDuration {
565565
seconds,
566566
fraction,
567567
} => {
568-
checked_write_with_suffix(hours, 'H', sink)?;
569-
checked_write_with_suffix(minutes, 'M', sink)?;
568+
checked_write_u64_with_suffix(hours, 'H', sink)?;
569+
checked_write_u64_with_suffix(minutes, 'M', sink)?;
570570
let unit_below_minute =
571-
self.duration.date.is_none() || hours != 0 || minutes != 0;
571+
self.duration.date.is_none() && hours == 0 && minutes == 0;
572572
if seconds != 0
573573
|| unit_below_minute
574574
|| matches!(self.precision, Precision::Digit(_))
575575
{
576576
seconds.write_to(sink)?;
577-
if self.precision == Precision::Auto
578-
|| self.precision == Precision::Digit(0)
579-
{
577+
if self.precision == Precision::Digit(0)
578+
|| (self.precision == Precision::Auto && fraction == 0) {
580579
sink.write_char('S')?;
581580
return Ok(());
582581
}
@@ -591,7 +590,7 @@ impl Writeable for FormattableDuration {
591590
}
592591
}
593592

594-
fn checked_write_with_suffix<W: core::fmt::Write + ?Sized>(
593+
fn checked_write_u32_with_suffix<W: core::fmt::Write + ?Sized>(
595594
val: u32,
596595
suffix: char,
597596
sink: &mut W,
@@ -603,6 +602,18 @@ fn checked_write_with_suffix<W: core::fmt::Write + ?Sized>(
603602
sink.write_char(suffix)
604603
}
605604

605+
fn checked_write_u64_with_suffix<W: core::fmt::Write + ?Sized>(
606+
val: u64,
607+
suffix: char,
608+
sink: &mut W,
609+
) -> core::fmt::Result {
610+
if val == 0 {
611+
return Ok(());
612+
}
613+
val.write_to(sink)?;
614+
sink.write_char(suffix)
615+
}
616+
606617
// TODO: Determine if these should be separate structs, i.e. TemporalDateTimeParser/TemporalInstantParser, or
607618
// maybe on global `TemporalParser` around `IxdtfParser` that handles the Temporal idiosyncracies.
608619
enum ParseVariant {

0 commit comments

Comments
 (0)