mirror of
https://github.com/BurntSushi/jiff.git
synced 2025-12-23 08:47:45 +00:00
fmt: add support for printing std::time::Duration
This was thankfully as straight-forward as I was hoping!
This commit is contained in:
parent
3e49cbed78
commit
8a7f2492fd
3 changed files with 969 additions and 22 deletions
|
|
@ -1035,6 +1035,49 @@ impl SpanPrinter {
|
|||
buf
|
||||
}
|
||||
|
||||
/// Format a `std::time::Duration` into a string using the "friendly"
|
||||
/// format.
|
||||
///
|
||||
/// This balances the units of the duration up to at most hours
|
||||
/// automatically.
|
||||
///
|
||||
/// This is a convenience routine for
|
||||
/// [`SpanPrinter::print_unsigned_duration`] with a `String`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// use jiff::fmt::friendly::{FractionalUnit, SpanPrinter};
|
||||
///
|
||||
/// static PRINTER: SpanPrinter = SpanPrinter::new();
|
||||
///
|
||||
/// let dur = Duration::new(86_525, 123_000_789);
|
||||
/// assert_eq!(
|
||||
/// PRINTER.unsigned_duration_to_string(&dur),
|
||||
/// "24h 2m 5s 123ms 789ns",
|
||||
/// );
|
||||
///
|
||||
/// // Or, if you prefer fractional seconds:
|
||||
/// static PRINTER_FRACTIONAL: SpanPrinter = SpanPrinter::new()
|
||||
/// .fractional(Some(FractionalUnit::Second));
|
||||
/// assert_eq!(
|
||||
/// PRINTER_FRACTIONAL.unsigned_duration_to_string(&dur),
|
||||
/// "24h 2m 5.123000789s",
|
||||
/// );
|
||||
/// ```
|
||||
#[cfg(any(test, feature = "alloc"))]
|
||||
pub fn unsigned_duration_to_string(
|
||||
&self,
|
||||
duration: &core::time::Duration,
|
||||
) -> alloc::string::String {
|
||||
let mut buf = alloc::string::String::with_capacity(4);
|
||||
// OK because writing to `String` never fails.
|
||||
self.print_unsigned_duration(duration, &mut buf).unwrap();
|
||||
buf
|
||||
}
|
||||
|
||||
/// Print a `Span` to the given writer using the "friendly" format.
|
||||
///
|
||||
/// # Errors
|
||||
|
|
@ -1112,6 +1155,46 @@ impl SpanPrinter {
|
|||
self.print_signed_duration_designators(duration, wtr)
|
||||
}
|
||||
|
||||
/// Print a `std::time::Duration` to the given writer using the "friendly"
|
||||
/// format.
|
||||
///
|
||||
/// This balances the units of the duration up to at most hours
|
||||
/// automatically.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This only returns an error when writing to the given [`Write`]
|
||||
/// implementation would fail. Some such implementations, like for `String`
|
||||
/// and `Vec<u8>`, never fail (unless memory allocation fails). In such
|
||||
/// cases, it would be appropriate to call `unwrap()` on the result.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// use jiff::fmt::friendly::SpanPrinter;
|
||||
///
|
||||
/// static PRINTER: SpanPrinter = SpanPrinter::new();
|
||||
///
|
||||
/// let dur = Duration::new(86_525, 123_000_789);
|
||||
///
|
||||
/// let mut buf = String::new();
|
||||
/// // Printing to a `String` can never fail.
|
||||
/// PRINTER.print_unsigned_duration(&dur, &mut buf).unwrap();
|
||||
/// assert_eq!(buf, "24h 2m 5s 123ms 789ns");
|
||||
/// ```
|
||||
pub fn print_unsigned_duration<W: Write>(
|
||||
&self,
|
||||
duration: &core::time::Duration,
|
||||
wtr: W,
|
||||
) -> Result<(), Error> {
|
||||
if self.hms {
|
||||
return self.print_unsigned_duration_hms(duration, wtr);
|
||||
}
|
||||
self.print_unsigned_duration_designators(duration, wtr)
|
||||
}
|
||||
|
||||
fn print_span_designators<W: Write>(
|
||||
&self,
|
||||
span: &Span,
|
||||
|
|
@ -1258,6 +1341,18 @@ impl SpanPrinter {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn print_unsigned_duration_designators<W: Write>(
|
||||
&self,
|
||||
dur: &core::time::Duration,
|
||||
mut wtr: W,
|
||||
) -> Result<(), Error> {
|
||||
let mut wtr = DesignatorWriter::new(self, &mut wtr, false, 1);
|
||||
wtr.maybe_write_prefix_sign()?;
|
||||
self.print_duration_designators(dur, &mut wtr)?;
|
||||
wtr.maybe_write_zero()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_duration_designators<W: Write>(
|
||||
&self,
|
||||
dur: &core::time::Duration,
|
||||
|
|
@ -1360,6 +1455,18 @@ impl SpanPrinter {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn print_unsigned_duration_hms<W: Write>(
|
||||
&self,
|
||||
dur: &core::time::Duration,
|
||||
mut wtr: W,
|
||||
) -> Result<(), Error> {
|
||||
if let Direction::ForceSign = self.direction {
|
||||
wtr.write_str("+")?;
|
||||
}
|
||||
self.print_duration_hms(dur, &mut wtr)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_duration_hms<W: Write>(
|
||||
&self,
|
||||
udur: &core::time::Duration,
|
||||
|
|
@ -2311,7 +2418,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_default() {
|
||||
fn print_signed_duration_designator_default() {
|
||||
let printer = || SpanPrinter::new();
|
||||
let p = |secs| {
|
||||
printer().duration_to_string(&SignedDuration::from_secs(secs))
|
||||
|
|
@ -2354,7 +2461,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_verbose() {
|
||||
fn print_signed_duration_designator_verbose() {
|
||||
let printer = || SpanPrinter::new().designator(Designator::Verbose);
|
||||
let p = |secs| {
|
||||
printer().duration_to_string(&SignedDuration::from_secs(secs))
|
||||
|
|
@ -2397,7 +2504,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_short() {
|
||||
fn print_signed_duration_designator_short() {
|
||||
let printer = || SpanPrinter::new().designator(Designator::Short);
|
||||
let p = |secs| {
|
||||
printer().duration_to_string(&SignedDuration::from_secs(secs))
|
||||
|
|
@ -2440,7 +2547,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_compact() {
|
||||
fn print_signed_duration_designator_compact() {
|
||||
let printer = || SpanPrinter::new().designator(Designator::Compact);
|
||||
let p = |secs| {
|
||||
printer().duration_to_string(&SignedDuration::from_secs(secs))
|
||||
|
|
@ -2483,7 +2590,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_direction_force() {
|
||||
fn print_signed_duration_designator_direction_force() {
|
||||
let printer = || SpanPrinter::new().direction(Direction::ForceSign);
|
||||
let p = |secs| {
|
||||
printer().duration_to_string(&SignedDuration::from_secs(secs))
|
||||
|
|
@ -2526,7 +2633,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_padding() {
|
||||
fn print_signed_duration_designator_padding() {
|
||||
let printer = || SpanPrinter::new().padding(2);
|
||||
let p = |secs| {
|
||||
printer().duration_to_string(&SignedDuration::from_secs(secs))
|
||||
|
|
@ -2569,7 +2676,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_spacing_none() {
|
||||
fn print_signed_duration_designator_spacing_none() {
|
||||
let printer = || SpanPrinter::new().spacing(Spacing::None);
|
||||
let p = |secs| {
|
||||
printer().duration_to_string(&SignedDuration::from_secs(secs))
|
||||
|
|
@ -2612,7 +2719,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_spacing_more() {
|
||||
fn print_signed_duration_designator_spacing_more() {
|
||||
let printer =
|
||||
|| SpanPrinter::new().spacing(Spacing::BetweenUnitsAndDesignators);
|
||||
let p = |secs| {
|
||||
|
|
@ -2656,7 +2763,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_spacing_comma() {
|
||||
fn print_signed_duration_designator_spacing_comma() {
|
||||
let printer = || {
|
||||
SpanPrinter::new()
|
||||
.comma_after_designator(true)
|
||||
|
|
@ -2703,7 +2810,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_fractional_hour() {
|
||||
fn print_signed_duration_designator_fractional_hour() {
|
||||
let printer =
|
||||
|| SpanPrinter::new().fractional(Some(FractionalUnit::Hour));
|
||||
let p = |secs, nanos| {
|
||||
|
|
@ -2741,7 +2848,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_fractional_minute() {
|
||||
fn print_signed_duration_designator_fractional_minute() {
|
||||
let printer =
|
||||
|| SpanPrinter::new().fractional(Some(FractionalUnit::Minute));
|
||||
let p = |secs, nanos| {
|
||||
|
|
@ -2783,7 +2890,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_fractional_second() {
|
||||
fn print_signed_duration_designator_fractional_second() {
|
||||
let printer =
|
||||
|| SpanPrinter::new().fractional(Some(FractionalUnit::Second));
|
||||
let p = |secs, nanos| {
|
||||
|
|
@ -2819,7 +2926,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_fractional_millisecond() {
|
||||
fn print_signed_duration_designator_fractional_millisecond() {
|
||||
let printer = || {
|
||||
SpanPrinter::new().fractional(Some(FractionalUnit::Millisecond))
|
||||
};
|
||||
|
|
@ -2860,7 +2967,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_designator_fractional_microsecond() {
|
||||
fn print_signed_duration_designator_fractional_microsecond() {
|
||||
let printer = || {
|
||||
SpanPrinter::new().fractional(Some(FractionalUnit::Microsecond))
|
||||
};
|
||||
|
|
@ -2900,6 +3007,572 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_default() {
|
||||
let printer = || SpanPrinter::new();
|
||||
let p = |secs| {
|
||||
printer().unsigned_duration_to_string(
|
||||
&core::time::Duration::from_secs(secs),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1), @"1s");
|
||||
insta::assert_snapshot!(p(2), @"2s");
|
||||
insta::assert_snapshot!(p(10), @"10s");
|
||||
insta::assert_snapshot!(p(100), @"1m 40s");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60), @"1m");
|
||||
insta::assert_snapshot!(p(2 * 60), @"2m");
|
||||
insta::assert_snapshot!(p(10 * 60), @"10m");
|
||||
insta::assert_snapshot!(p(100 * 60), @"1h 40m");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
|
||||
insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
|
||||
insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
|
||||
insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(60 * 60 + 60 + 1),
|
||||
@"1h 1m 1s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(2 * 60 * 60 + 2 * 60 + 2),
|
||||
@"2h 2m 2s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(10 * 60 * 60 + 10 * 60 + 10),
|
||||
@"10h 10m 10s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(100 * 60 * 60 + 100 * 60 + 100),
|
||||
@"101h 41m 40s",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_verbose() {
|
||||
let printer = || SpanPrinter::new().designator(Designator::Verbose);
|
||||
let p = |secs| {
|
||||
printer().unsigned_duration_to_string(
|
||||
&core::time::Duration::from_secs(secs),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1), @"1second");
|
||||
insta::assert_snapshot!(p(2), @"2seconds");
|
||||
insta::assert_snapshot!(p(10), @"10seconds");
|
||||
insta::assert_snapshot!(p(100), @"1minute 40seconds");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60), @"1minute");
|
||||
insta::assert_snapshot!(p(2 * 60), @"2minutes");
|
||||
insta::assert_snapshot!(p(10 * 60), @"10minutes");
|
||||
insta::assert_snapshot!(p(100 * 60), @"1hour 40minutes");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60), @"1hour");
|
||||
insta::assert_snapshot!(p(2 * 60 * 60), @"2hours");
|
||||
insta::assert_snapshot!(p(10 * 60 * 60), @"10hours");
|
||||
insta::assert_snapshot!(p(100 * 60 * 60), @"100hours");
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(60 * 60 + 60 + 1),
|
||||
@"1hour 1minute 1second",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(2 * 60 * 60 + 2 * 60 + 2),
|
||||
@"2hours 2minutes 2seconds",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(10 * 60 * 60 + 10 * 60 + 10),
|
||||
@"10hours 10minutes 10seconds",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(100 * 60 * 60 + 100 * 60 + 100),
|
||||
@"101hours 41minutes 40seconds",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_short() {
|
||||
let printer = || SpanPrinter::new().designator(Designator::Short);
|
||||
let p = |secs| {
|
||||
printer().unsigned_duration_to_string(
|
||||
&core::time::Duration::from_secs(secs),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1), @"1sec");
|
||||
insta::assert_snapshot!(p(2), @"2secs");
|
||||
insta::assert_snapshot!(p(10), @"10secs");
|
||||
insta::assert_snapshot!(p(100), @"1min 40secs");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60), @"1min");
|
||||
insta::assert_snapshot!(p(2 * 60), @"2mins");
|
||||
insta::assert_snapshot!(p(10 * 60), @"10mins");
|
||||
insta::assert_snapshot!(p(100 * 60), @"1hr 40mins");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60), @"1hr");
|
||||
insta::assert_snapshot!(p(2 * 60 * 60), @"2hrs");
|
||||
insta::assert_snapshot!(p(10 * 60 * 60), @"10hrs");
|
||||
insta::assert_snapshot!(p(100 * 60 * 60), @"100hrs");
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(60 * 60 + 60 + 1),
|
||||
@"1hr 1min 1sec",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(2 * 60 * 60 + 2 * 60 + 2),
|
||||
@"2hrs 2mins 2secs",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(10 * 60 * 60 + 10 * 60 + 10),
|
||||
@"10hrs 10mins 10secs",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(100 * 60 * 60 + 100 * 60 + 100),
|
||||
@"101hrs 41mins 40secs",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_compact() {
|
||||
let printer = || SpanPrinter::new().designator(Designator::Compact);
|
||||
let p = |secs| {
|
||||
printer().unsigned_duration_to_string(
|
||||
&core::time::Duration::from_secs(secs),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1), @"1s");
|
||||
insta::assert_snapshot!(p(2), @"2s");
|
||||
insta::assert_snapshot!(p(10), @"10s");
|
||||
insta::assert_snapshot!(p(100), @"1m 40s");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60), @"1m");
|
||||
insta::assert_snapshot!(p(2 * 60), @"2m");
|
||||
insta::assert_snapshot!(p(10 * 60), @"10m");
|
||||
insta::assert_snapshot!(p(100 * 60), @"1h 40m");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
|
||||
insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
|
||||
insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
|
||||
insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(60 * 60 + 60 + 1),
|
||||
@"1h 1m 1s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(2 * 60 * 60 + 2 * 60 + 2),
|
||||
@"2h 2m 2s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(10 * 60 * 60 + 10 * 60 + 10),
|
||||
@"10h 10m 10s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(100 * 60 * 60 + 100 * 60 + 100),
|
||||
@"101h 41m 40s",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_direction_force() {
|
||||
let printer = || SpanPrinter::new().direction(Direction::ForceSign);
|
||||
let p = |secs| {
|
||||
printer().unsigned_duration_to_string(
|
||||
&core::time::Duration::from_secs(secs),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1), @"+1s");
|
||||
insta::assert_snapshot!(p(2), @"+2s");
|
||||
insta::assert_snapshot!(p(10), @"+10s");
|
||||
insta::assert_snapshot!(p(100), @"+1m 40s");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60), @"+1m");
|
||||
insta::assert_snapshot!(p(2 * 60), @"+2m");
|
||||
insta::assert_snapshot!(p(10 * 60), @"+10m");
|
||||
insta::assert_snapshot!(p(100 * 60), @"+1h 40m");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60), @"+1h");
|
||||
insta::assert_snapshot!(p(2 * 60 * 60), @"+2h");
|
||||
insta::assert_snapshot!(p(10 * 60 * 60), @"+10h");
|
||||
insta::assert_snapshot!(p(100 * 60 * 60), @"+100h");
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(60 * 60 + 60 + 1),
|
||||
@"+1h 1m 1s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(2 * 60 * 60 + 2 * 60 + 2),
|
||||
@"+2h 2m 2s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(10 * 60 * 60 + 10 * 60 + 10),
|
||||
@"+10h 10m 10s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(100 * 60 * 60 + 100 * 60 + 100),
|
||||
@"+101h 41m 40s",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_padding() {
|
||||
let printer = || SpanPrinter::new().padding(2);
|
||||
let p = |secs| {
|
||||
printer().unsigned_duration_to_string(
|
||||
&core::time::Duration::from_secs(secs),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1), @"01s");
|
||||
insta::assert_snapshot!(p(2), @"02s");
|
||||
insta::assert_snapshot!(p(10), @"10s");
|
||||
insta::assert_snapshot!(p(100), @"01m 40s");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60), @"01m");
|
||||
insta::assert_snapshot!(p(2 * 60), @"02m");
|
||||
insta::assert_snapshot!(p(10 * 60), @"10m");
|
||||
insta::assert_snapshot!(p(100 * 60), @"01h 40m");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60), @"01h");
|
||||
insta::assert_snapshot!(p(2 * 60 * 60), @"02h");
|
||||
insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
|
||||
insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(60 * 60 + 60 + 1),
|
||||
@"01h 01m 01s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(2 * 60 * 60 + 2 * 60 + 2),
|
||||
@"02h 02m 02s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(10 * 60 * 60 + 10 * 60 + 10),
|
||||
@"10h 10m 10s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(100 * 60 * 60 + 100 * 60 + 100),
|
||||
@"101h 41m 40s",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_spacing_none() {
|
||||
let printer = || SpanPrinter::new().spacing(Spacing::None);
|
||||
let p = |secs| {
|
||||
printer().unsigned_duration_to_string(
|
||||
&core::time::Duration::from_secs(secs),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1), @"1s");
|
||||
insta::assert_snapshot!(p(2), @"2s");
|
||||
insta::assert_snapshot!(p(10), @"10s");
|
||||
insta::assert_snapshot!(p(100), @"1m40s");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60), @"1m");
|
||||
insta::assert_snapshot!(p(2 * 60), @"2m");
|
||||
insta::assert_snapshot!(p(10 * 60), @"10m");
|
||||
insta::assert_snapshot!(p(100 * 60), @"1h40m");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
|
||||
insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
|
||||
insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
|
||||
insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(60 * 60 + 60 + 1),
|
||||
@"1h1m1s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(2 * 60 * 60 + 2 * 60 + 2),
|
||||
@"2h2m2s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(10 * 60 * 60 + 10 * 60 + 10),
|
||||
@"10h10m10s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(100 * 60 * 60 + 100 * 60 + 100),
|
||||
@"101h41m40s",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_spacing_more() {
|
||||
let printer =
|
||||
|| SpanPrinter::new().spacing(Spacing::BetweenUnitsAndDesignators);
|
||||
let p = |secs| {
|
||||
printer().unsigned_duration_to_string(
|
||||
&core::time::Duration::from_secs(secs),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1), @"1 s");
|
||||
insta::assert_snapshot!(p(2), @"2 s");
|
||||
insta::assert_snapshot!(p(10), @"10 s");
|
||||
insta::assert_snapshot!(p(100), @"1 m 40 s");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60), @"1 m");
|
||||
insta::assert_snapshot!(p(2 * 60), @"2 m");
|
||||
insta::assert_snapshot!(p(10 * 60), @"10 m");
|
||||
insta::assert_snapshot!(p(100 * 60), @"1 h 40 m");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60), @"1 h");
|
||||
insta::assert_snapshot!(p(2 * 60 * 60), @"2 h");
|
||||
insta::assert_snapshot!(p(10 * 60 * 60), @"10 h");
|
||||
insta::assert_snapshot!(p(100 * 60 * 60), @"100 h");
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(60 * 60 + 60 + 1),
|
||||
@"1 h 1 m 1 s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(2 * 60 * 60 + 2 * 60 + 2),
|
||||
@"2 h 2 m 2 s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(10 * 60 * 60 + 10 * 60 + 10),
|
||||
@"10 h 10 m 10 s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(100 * 60 * 60 + 100 * 60 + 100),
|
||||
@"101 h 41 m 40 s",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_spacing_comma() {
|
||||
let printer = || {
|
||||
SpanPrinter::new()
|
||||
.comma_after_designator(true)
|
||||
.spacing(Spacing::BetweenUnitsAndDesignators)
|
||||
};
|
||||
let p = |secs| {
|
||||
printer().unsigned_duration_to_string(
|
||||
&core::time::Duration::from_secs(secs),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1), @"1 s");
|
||||
insta::assert_snapshot!(p(2), @"2 s");
|
||||
insta::assert_snapshot!(p(10), @"10 s");
|
||||
insta::assert_snapshot!(p(100), @"1 m, 40 s");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60), @"1 m");
|
||||
insta::assert_snapshot!(p(2 * 60), @"2 m");
|
||||
insta::assert_snapshot!(p(10 * 60), @"10 m");
|
||||
insta::assert_snapshot!(p(100 * 60), @"1 h, 40 m");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60), @"1 h");
|
||||
insta::assert_snapshot!(p(2 * 60 * 60), @"2 h");
|
||||
insta::assert_snapshot!(p(10 * 60 * 60), @"10 h");
|
||||
insta::assert_snapshot!(p(100 * 60 * 60), @"100 h");
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(60 * 60 + 60 + 1),
|
||||
@"1 h, 1 m, 1 s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(2 * 60 * 60 + 2 * 60 + 2),
|
||||
@"2 h, 2 m, 2 s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(10 * 60 * 60 + 10 * 60 + 10),
|
||||
@"10 h, 10 m, 10 s",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(100 * 60 * 60 + 100 * 60 + 100),
|
||||
@"101 h, 41 m, 40 s",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_fractional_hour() {
|
||||
let printer =
|
||||
|| SpanPrinter::new().fractional(Some(FractionalUnit::Hour));
|
||||
let p = |secs, nanos| {
|
||||
printer().unsigned_duration_to_string(&core::time::Duration::new(
|
||||
secs, nanos,
|
||||
))
|
||||
};
|
||||
let pp = |precision, secs, nanos| {
|
||||
printer()
|
||||
.precision(Some(precision))
|
||||
.duration_to_string(&SignedDuration::new(secs, nanos))
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
|
||||
insta::assert_snapshot!(pp(0, 1 * 60 * 60, 0), @"1h");
|
||||
insta::assert_snapshot!(pp(1, 1 * 60 * 60, 0), @"1.0h");
|
||||
insta::assert_snapshot!(pp(2, 1 * 60 * 60, 0), @"1.00h");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1.5h");
|
||||
insta::assert_snapshot!(pp(0, 1 * 60 * 60 + 30 * 60, 0), @"1h");
|
||||
insta::assert_snapshot!(pp(1, 1 * 60 * 60 + 30 * 60, 0), @"1.5h");
|
||||
insta::assert_snapshot!(pp(2, 1 * 60 * 60 + 30 * 60, 0), @"1.50h");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60 + 3 * 60, 0), @"1.05h");
|
||||
insta::assert_snapshot!(p(1 * 60 * 60 + 3 * 60, 1), @"1.05h");
|
||||
insta::assert_snapshot!(p(1, 0), @"0.000277777h");
|
||||
// precision loss!
|
||||
insta::assert_snapshot!(p(1, 1), @"0.000277777h");
|
||||
insta::assert_snapshot!(p(0, 0), @"0h");
|
||||
// precision loss!
|
||||
insta::assert_snapshot!(p(0, 1), @"0h");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_fractional_minute() {
|
||||
let printer =
|
||||
|| SpanPrinter::new().fractional(Some(FractionalUnit::Minute));
|
||||
let p = |secs, nanos| {
|
||||
printer().unsigned_duration_to_string(&core::time::Duration::new(
|
||||
secs, nanos,
|
||||
))
|
||||
};
|
||||
let pp = |precision, secs, nanos| {
|
||||
printer()
|
||||
.precision(Some(precision))
|
||||
.duration_to_string(&SignedDuration::new(secs, nanos))
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
|
||||
insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
|
||||
|
||||
insta::assert_snapshot!(p(60, 0), @"1m");
|
||||
insta::assert_snapshot!(pp(0, 60, 0), @"1m");
|
||||
insta::assert_snapshot!(pp(1, 60, 0), @"1.0m");
|
||||
insta::assert_snapshot!(pp(2, 60, 0), @"1.00m");
|
||||
|
||||
insta::assert_snapshot!(p(90, 0), @"1.5m");
|
||||
insta::assert_snapshot!(pp(0, 90, 0), @"1m");
|
||||
insta::assert_snapshot!(pp(1, 90, 0), @"1.5m");
|
||||
insta::assert_snapshot!(pp(2, 90, 0), @"1.50m");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60, 1), @"1h");
|
||||
insta::assert_snapshot!(p(63, 0), @"1.05m");
|
||||
insta::assert_snapshot!(p(63, 1), @"1.05m");
|
||||
insta::assert_snapshot!(p(1, 0), @"0.016666666m");
|
||||
// precision loss!
|
||||
insta::assert_snapshot!(p(1, 1), @"0.016666666m");
|
||||
insta::assert_snapshot!(p(0, 0), @"0m");
|
||||
// precision loss!
|
||||
insta::assert_snapshot!(p(0, 1), @"0m");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_fractional_second() {
|
||||
let printer =
|
||||
|| SpanPrinter::new().fractional(Some(FractionalUnit::Second));
|
||||
let p = |secs, nanos| {
|
||||
printer().unsigned_duration_to_string(&core::time::Duration::new(
|
||||
secs, nanos,
|
||||
))
|
||||
};
|
||||
let pp = |precision, secs, nanos| {
|
||||
printer()
|
||||
.precision(Some(precision))
|
||||
.duration_to_string(&SignedDuration::new(secs, nanos))
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
|
||||
insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
|
||||
|
||||
insta::assert_snapshot!(p(1, 0), @"1s");
|
||||
insta::assert_snapshot!(pp(0, 1, 0), @"1s");
|
||||
insta::assert_snapshot!(pp(1, 1, 0), @"1.0s");
|
||||
insta::assert_snapshot!(pp(2, 1, 0), @"1.00s");
|
||||
|
||||
insta::assert_snapshot!(p(1, 500_000_000), @"1.5s");
|
||||
insta::assert_snapshot!(pp(0, 1, 500_000_000), @"1s");
|
||||
insta::assert_snapshot!(pp(1, 1, 500_000_000), @"1.5s");
|
||||
insta::assert_snapshot!(pp(2, 1, 500_000_000), @"1.50s");
|
||||
|
||||
insta::assert_snapshot!(p(1, 1), @"1.000000001s");
|
||||
insta::assert_snapshot!(p(0, 1), @"0.000000001s");
|
||||
insta::assert_snapshot!(p(0, 0), @"0s");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_fractional_millisecond() {
|
||||
let printer = || {
|
||||
SpanPrinter::new().fractional(Some(FractionalUnit::Millisecond))
|
||||
};
|
||||
let p = |secs, nanos| {
|
||||
printer().unsigned_duration_to_string(&core::time::Duration::new(
|
||||
secs, nanos,
|
||||
))
|
||||
};
|
||||
let pp = |precision, secs, nanos| {
|
||||
printer()
|
||||
.precision(Some(precision))
|
||||
.duration_to_string(&SignedDuration::new(secs, nanos))
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
|
||||
insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
|
||||
insta::assert_snapshot!(
|
||||
p(1 * 60 * 60 + 30 * 60 + 10, 0),
|
||||
@"1h 30m 10s",
|
||||
);
|
||||
|
||||
insta::assert_snapshot!(p(1, 0), @"1s");
|
||||
insta::assert_snapshot!(pp(0, 1, 0), @"1s");
|
||||
insta::assert_snapshot!(pp(1, 1, 0), @"1s 0.0ms");
|
||||
insta::assert_snapshot!(pp(2, 1, 0), @"1s 0.00ms");
|
||||
|
||||
insta::assert_snapshot!(p(1, 500_000_000), @"1s 500ms");
|
||||
insta::assert_snapshot!(pp(0, 1, 1_500_000), @"1s 1ms");
|
||||
insta::assert_snapshot!(pp(1, 1, 1_500_000), @"1s 1.5ms");
|
||||
insta::assert_snapshot!(pp(2, 1, 1_500_000), @"1s 1.50ms");
|
||||
|
||||
insta::assert_snapshot!(p(0, 1_000_001), @"1.000001ms");
|
||||
insta::assert_snapshot!(p(0, 0_000_001), @"0.000001ms");
|
||||
insta::assert_snapshot!(p(0, 0), @"0ms");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_designator_fractional_microsecond() {
|
||||
let printer = || {
|
||||
SpanPrinter::new().fractional(Some(FractionalUnit::Microsecond))
|
||||
};
|
||||
let p = |secs, nanos| {
|
||||
printer().unsigned_duration_to_string(&core::time::Duration::new(
|
||||
secs, nanos,
|
||||
))
|
||||
};
|
||||
let pp = |precision, secs, nanos| {
|
||||
printer().precision(Some(precision)).unsigned_duration_to_string(
|
||||
&core::time::Duration::new(secs, nanos),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
|
||||
insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
|
||||
insta::assert_snapshot!(
|
||||
p(1 * 60 * 60 + 30 * 60 + 10, 0),
|
||||
@"1h 30m 10s",
|
||||
);
|
||||
|
||||
insta::assert_snapshot!(p(1, 0), @"1s");
|
||||
insta::assert_snapshot!(pp(0, 1, 0), @"1s");
|
||||
insta::assert_snapshot!(pp(1, 1, 0), @"1s 0.0µs");
|
||||
insta::assert_snapshot!(pp(2, 1, 0), @"1s 0.00µs");
|
||||
|
||||
insta::assert_snapshot!(p(1, 500_000_000), @"1s 500ms");
|
||||
insta::assert_snapshot!(pp(0, 1, 1_500_000), @"1s 1ms 500µs");
|
||||
insta::assert_snapshot!(pp(1, 1, 1_500_000), @"1s 1ms 500.0µs");
|
||||
insta::assert_snapshot!(pp(2, 1, 1_500_000), @"1s 1ms 500.00µs");
|
||||
|
||||
insta::assert_snapshot!(p(0, 1_000_001), @"1ms 0.001µs");
|
||||
insta::assert_snapshot!(p(0, 0_000_001), @"0.001µs");
|
||||
insta::assert_snapshot!(p(0, 0), @"0µs");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_span_hms() {
|
||||
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
|
||||
|
|
@ -3112,7 +3785,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_hms() {
|
||||
fn print_signed_duration_hms() {
|
||||
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
|
||||
let p = |secs| {
|
||||
printer().duration_to_string(&SignedDuration::from_secs(secs))
|
||||
|
|
@ -3155,7 +3828,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_hms_sign() {
|
||||
fn print_signed_duration_hms_sign() {
|
||||
let printer = |direction| {
|
||||
SpanPrinter::new().hours_minutes_seconds(true).direction(direction)
|
||||
};
|
||||
|
|
@ -3176,7 +3849,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_hms_fraction_auto() {
|
||||
fn print_signed_duration_hms_fraction_auto() {
|
||||
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
|
||||
let p = |secs, nanos| {
|
||||
printer().duration_to_string(&SignedDuration::new(secs, nanos))
|
||||
|
|
@ -3210,7 +3883,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration_hms_fraction_fixed_precision() {
|
||||
fn print_signed_duration_hms_fraction_fixed_precision() {
|
||||
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
|
||||
let p = |precision, secs, nanos| {
|
||||
printer()
|
||||
|
|
@ -3239,4 +3912,132 @@ mod tests {
|
|||
@"00:00:01.9",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_hms() {
|
||||
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
|
||||
let p = |secs| {
|
||||
printer().unsigned_duration_to_string(
|
||||
&core::time::Duration::from_secs(secs),
|
||||
)
|
||||
};
|
||||
|
||||
// Note the differences with `Span`, since with a `Duration`,
|
||||
// all units are balanced.
|
||||
|
||||
insta::assert_snapshot!(p(1), @"00:00:01");
|
||||
insta::assert_snapshot!(p(2), @"00:00:02");
|
||||
insta::assert_snapshot!(p(10), @"00:00:10");
|
||||
insta::assert_snapshot!(p(100), @"00:01:40");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60), @"00:01:00");
|
||||
insta::assert_snapshot!(p(2 * 60), @"00:02:00");
|
||||
insta::assert_snapshot!(p(10 * 60), @"00:10:00");
|
||||
insta::assert_snapshot!(p(100 * 60), @"01:40:00");
|
||||
|
||||
insta::assert_snapshot!(p(1 * 60 * 60), @"01:00:00");
|
||||
insta::assert_snapshot!(p(2 * 60 * 60), @"02:00:00");
|
||||
insta::assert_snapshot!(p(10 * 60 * 60), @"10:00:00");
|
||||
insta::assert_snapshot!(p(100 * 60 * 60), @"100:00:00");
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(60 * 60 + 60 + 1),
|
||||
@"01:01:01",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(2 * 60 * 60 + 2 * 60 + 2),
|
||||
@"02:02:02",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(10 * 60 * 60 + 10 * 60 + 10),
|
||||
@"10:10:10",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(100 * 60 * 60 + 100 * 60 + 100),
|
||||
@"101:41:40",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_hms_sign() {
|
||||
let printer = |direction| {
|
||||
SpanPrinter::new().hours_minutes_seconds(true).direction(direction)
|
||||
};
|
||||
let p = |direction, secs| {
|
||||
printer(direction).unsigned_duration_to_string(
|
||||
&core::time::Duration::from_secs(secs),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(Direction::Auto, 1), @"00:00:01");
|
||||
insta::assert_snapshot!(p(Direction::Sign, 1), @"00:00:01");
|
||||
insta::assert_snapshot!(p(Direction::ForceSign, 1), @"+00:00:01");
|
||||
insta::assert_snapshot!(p(Direction::Suffix, 1), @"00:00:01");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_hms_fraction_auto() {
|
||||
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
|
||||
let p = |secs, nanos| {
|
||||
printer().unsigned_duration_to_string(&core::time::Duration::new(
|
||||
secs, nanos,
|
||||
))
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(0, 1), @"00:00:00.000000001");
|
||||
insta::assert_snapshot!(
|
||||
printer().direction(Direction::ForceSign).duration_to_string(
|
||||
&SignedDuration::new(0, 1),
|
||||
),
|
||||
@"+00:00:00.000000001",
|
||||
);
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(1, 123),
|
||||
@"00:00:01.000000123",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(1, 123_000_000),
|
||||
@"00:00:01.123",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(1, 1_123_000_000),
|
||||
@"00:00:02.123",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(61, 1_123_000_000),
|
||||
@"00:01:02.123",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration_hms_fraction_fixed_precision() {
|
||||
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
|
||||
let p = |precision, secs, nanos| {
|
||||
printer().precision(Some(precision)).unsigned_duration_to_string(
|
||||
&core::time::Duration::new(secs, nanos),
|
||||
)
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(3, 1, 0), @"00:00:01.000");
|
||||
insta::assert_snapshot!(
|
||||
p(3, 1, 1_000_000),
|
||||
@"00:00:01.001",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(3, 1, 123_000_000),
|
||||
@"00:00:01.123",
|
||||
);
|
||||
insta::assert_snapshot!(
|
||||
p(3, 1, 100_000_000),
|
||||
@"00:00:01.100",
|
||||
);
|
||||
|
||||
insta::assert_snapshot!(p(0, 1, 0), @"00:00:01");
|
||||
insta::assert_snapshot!(p(0, 1, 1_000_000), @"00:00:01");
|
||||
insta::assert_snapshot!(
|
||||
p(1, 1, 999_000_000),
|
||||
@"00:00:01.9",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2240,6 +2240,42 @@ impl SpanPrinter {
|
|||
buf
|
||||
}
|
||||
|
||||
/// Format a `std::time::Duration` into a string.
|
||||
///
|
||||
/// This balances the units of the duration up to at most hours
|
||||
/// automatically.
|
||||
///
|
||||
/// This is a convenience routine for
|
||||
/// [`SpanPrinter::print_unsigned_duration`] with a `String`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// use jiff::fmt::temporal::SpanPrinter;
|
||||
///
|
||||
/// const PRINTER: SpanPrinter = SpanPrinter::new();
|
||||
///
|
||||
/// let dur = Duration::new(86_525, 123_000_789);
|
||||
/// assert_eq!(
|
||||
/// PRINTER.unsigned_duration_to_string(&dur),
|
||||
/// "PT24H2M5.123000789S",
|
||||
/// );
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[cfg(feature = "alloc")]
|
||||
pub fn unsigned_duration_to_string(
|
||||
&self,
|
||||
duration: &core::time::Duration,
|
||||
) -> alloc::string::String {
|
||||
let mut buf = alloc::string::String::with_capacity(4);
|
||||
// OK because writing to `String` never fails.
|
||||
self.print_unsigned_duration(duration, &mut buf).unwrap();
|
||||
buf
|
||||
}
|
||||
|
||||
/// Print a `Span` to the given writer.
|
||||
///
|
||||
/// # Errors
|
||||
|
|
@ -2311,7 +2347,44 @@ impl SpanPrinter {
|
|||
duration: &SignedDuration,
|
||||
wtr: W,
|
||||
) -> Result<(), Error> {
|
||||
self.p.print_duration(duration, wtr)
|
||||
self.p.print_signed_duration(duration, wtr)
|
||||
}
|
||||
|
||||
/// Print a `std::time::Duration` to the given writer.
|
||||
///
|
||||
/// This balances the units of the duration up to at most hours
|
||||
/// automatically.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This only returns an error when writing to the given [`Write`]
|
||||
/// implementation would fail. Some such implementations, like for `String`
|
||||
/// and `Vec<u8>`, never fail (unless memory allocation fails). In such
|
||||
/// cases, it would be appropriate to call `unwrap()` on the result.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::Duration;
|
||||
/// use jiff::fmt::temporal::SpanPrinter;
|
||||
///
|
||||
/// const PRINTER: SpanPrinter = SpanPrinter::new();
|
||||
///
|
||||
/// let dur = Duration::new(86_525, 123_000_789);
|
||||
///
|
||||
/// let mut buf = String::new();
|
||||
/// // Printing to a `String` can never fail.
|
||||
/// PRINTER.print_unsigned_duration(&dur, &mut buf).unwrap();
|
||||
/// assert_eq!(buf, "PT24H2M5.123000789S");
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
pub fn print_unsigned_duration<W: Write>(
|
||||
&self,
|
||||
duration: &core::time::Duration,
|
||||
wtr: W,
|
||||
) -> Result<(), Error> {
|
||||
self.p.print_unsigned_duration(duration, wtr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ impl SpanPrinter {
|
|||
/// Print the given signed duration to the writer given.
|
||||
///
|
||||
/// This only returns an error when the given writer returns an error.
|
||||
pub(super) fn print_duration<W: Write>(
|
||||
pub(super) fn print_signed_duration<W: Write>(
|
||||
&self,
|
||||
dur: &SignedDuration,
|
||||
mut wtr: W,
|
||||
|
|
@ -560,6 +560,48 @@ impl SpanPrinter {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Print the given unsigned duration to the writer given.
|
||||
///
|
||||
/// This only returns an error when the given writer returns an error.
|
||||
pub(super) fn print_unsigned_duration<W: Write>(
|
||||
&self,
|
||||
dur: &core::time::Duration,
|
||||
mut wtr: W,
|
||||
) -> Result<(), Error> {
|
||||
static FMT_INT: DecimalFormatter = DecimalFormatter::new();
|
||||
static FMT_FRACTION: FractionalFormatter = FractionalFormatter::new();
|
||||
|
||||
let mut non_zero_greater_than_second = false;
|
||||
wtr.write_str("PT")?;
|
||||
|
||||
let mut secs = dur.as_secs();
|
||||
let nanos = dur.subsec_nanos();
|
||||
let hours = secs / (60 * 60);
|
||||
secs %= 60 * 60;
|
||||
let minutes = secs / 60;
|
||||
secs = secs % 60;
|
||||
if hours != 0 {
|
||||
wtr.write_uint(&FMT_INT, hours)?;
|
||||
wtr.write_char(self.label('H'))?;
|
||||
non_zero_greater_than_second = true;
|
||||
}
|
||||
if minutes != 0 {
|
||||
wtr.write_uint(&FMT_INT, minutes)?;
|
||||
wtr.write_char(self.label('M'))?;
|
||||
non_zero_greater_than_second = true;
|
||||
}
|
||||
if (secs != 0 || !non_zero_greater_than_second) && nanos == 0 {
|
||||
wtr.write_uint(&FMT_INT, secs)?;
|
||||
wtr.write_char(self.label('S'))?;
|
||||
} else if nanos != 0 {
|
||||
wtr.write_uint(&FMT_INT, secs)?;
|
||||
wtr.write_str(".")?;
|
||||
wtr.write_fraction(&FMT_FRACTION, nanos)?;
|
||||
wtr.write_char(self.label('S'))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Converts the uppercase unit designator label to lowercase if this
|
||||
/// printer is configured to use lowercase. Otherwise the label is returned
|
||||
/// unchanged.
|
||||
|
|
@ -805,11 +847,11 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn print_duration() {
|
||||
fn print_signed_duration() {
|
||||
let p = |secs, nanos| -> String {
|
||||
let dur = SignedDuration::new(secs, nanos);
|
||||
let mut buf = String::new();
|
||||
SpanPrinter::new().print_duration(&dur, &mut buf).unwrap();
|
||||
SpanPrinter::new().print_signed_duration(&dur, &mut buf).unwrap();
|
||||
buf
|
||||
};
|
||||
|
||||
|
|
@ -849,4 +891,35 @@ mod tests {
|
|||
@"PT2562047788015215H30M7.999999999S",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_unsigned_duration() {
|
||||
let p = |secs, nanos| -> String {
|
||||
let dur = core::time::Duration::new(secs, nanos);
|
||||
let mut buf = String::new();
|
||||
SpanPrinter::new()
|
||||
.print_unsigned_duration(&dur, &mut buf)
|
||||
.unwrap();
|
||||
buf
|
||||
};
|
||||
|
||||
insta::assert_snapshot!(p(0, 0), @"PT0S");
|
||||
insta::assert_snapshot!(p(0, 1), @"PT0.000000001S");
|
||||
insta::assert_snapshot!(p(1, 0), @"PT1S");
|
||||
insta::assert_snapshot!(p(59, 0), @"PT59S");
|
||||
insta::assert_snapshot!(p(60, 0), @"PT1M");
|
||||
insta::assert_snapshot!(p(60, 1), @"PT1M0.000000001S");
|
||||
insta::assert_snapshot!(p(61, 1), @"PT1M1.000000001S");
|
||||
insta::assert_snapshot!(p(3_600, 0), @"PT1H");
|
||||
insta::assert_snapshot!(p(3_600, 1), @"PT1H0.000000001S");
|
||||
insta::assert_snapshot!(p(3_660, 0), @"PT1H1M");
|
||||
insta::assert_snapshot!(p(3_660, 1), @"PT1H1M0.000000001S");
|
||||
insta::assert_snapshot!(p(3_661, 0), @"PT1H1M1S");
|
||||
insta::assert_snapshot!(p(3_661, 1), @"PT1H1M1.000000001S");
|
||||
|
||||
insta::assert_snapshot!(
|
||||
p(u64::MAX, 999_999_999),
|
||||
@"PT5124095576030431H15.999999999S",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue