use crate::{
fmt::{
util::{DecimalFormatter, FractionalFormatter},
Write, WriteExt,
},
Error, SignedDuration, Span, Unit,
};
const SECS_PER_HOUR: i64 = MINS_PER_HOUR * SECS_PER_MIN;
const SECS_PER_MIN: i64 = 60;
const MINS_PER_HOUR: i64 = 60;
const NANOS_PER_HOUR: i128 =
(SECS_PER_MIN * MINS_PER_HOUR * NANOS_PER_SEC) as i128;
const NANOS_PER_MIN: i128 = (SECS_PER_MIN * NANOS_PER_SEC) as i128;
const NANOS_PER_SEC: i64 = 1_000_000_000;
const NANOS_PER_MILLI: i32 = 1_000_000;
const NANOS_PER_MICRO: i32 = 1_000;
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub enum Designator {
Verbose,
Short,
Compact,
HumanTime,
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub enum Spacing {
None,
BetweenUnits,
BetweenUnitsAndDesignators,
}
impl Spacing {
fn between_units(self) -> &'static str {
match self {
Spacing::None => "",
Spacing::BetweenUnits => " ",
Spacing::BetweenUnitsAndDesignators => " ",
}
}
fn between_units_and_designators(self) -> &'static str {
match self {
Spacing::None => "",
Spacing::BetweenUnits => "",
Spacing::BetweenUnitsAndDesignators => " ",
}
}
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub enum Direction {
Auto,
Sign,
ForceSign,
Suffix,
}
impl Direction {
fn sign(
self,
printer: &SpanPrinter,
has_calendar: bool,
signum: i8,
) -> Option<DirectionSign> {
match self {
Direction::Auto => match printer.spacing {
Spacing::None => {
if signum < 0 {
Some(DirectionSign::Prefix("-"))
} else {
None
}
}
Spacing::BetweenUnits
| Spacing::BetweenUnitsAndDesignators => {
if signum < 0 {
if printer.hms && !has_calendar {
Some(DirectionSign::Prefix("-"))
} else {
Some(DirectionSign::Suffix(" ago"))
}
} else {
None
}
}
},
Direction::Sign => {
if signum < 0 {
Some(DirectionSign::Prefix("-"))
} else {
None
}
}
Direction::ForceSign => {
Some(DirectionSign::Prefix(if signum < 0 { "-" } else { "+" }))
}
Direction::Suffix => {
if signum < 0 {
Some(DirectionSign::Suffix(" ago"))
} else {
None
}
}
}
}
}
#[derive(Clone, Copy, Debug)]
enum DirectionSign {
Prefix(&'static str),
Suffix(&'static str),
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub enum FractionalUnit {
Hour,
Minute,
Second,
Millisecond,
Microsecond,
}
impl From<FractionalUnit> for Unit {
fn from(u: FractionalUnit) -> Unit {
match u {
FractionalUnit::Hour => Unit::Hour,
FractionalUnit::Minute => Unit::Minute,
FractionalUnit::Second => Unit::Second,
FractionalUnit::Millisecond => Unit::Millisecond,
FractionalUnit::Microsecond => Unit::Microsecond,
}
}
}
#[derive(Clone, Debug)]
pub struct SpanPrinter {
designator: Designator,
spacing: Spacing,
direction: Direction,
fractional: Option<FractionalUnit>,
comma_after_designator: bool,
hms: bool,
padding: Option<u8>,
precision: Option<u8>,
zero_unit: Unit,
}
impl SpanPrinter {
#[inline]
pub const fn new() -> SpanPrinter {
SpanPrinter {
designator: Designator::Compact,
spacing: Spacing::BetweenUnits,
direction: Direction::Auto,
fractional: None,
comma_after_designator: false,
hms: false,
padding: None,
precision: None,
zero_unit: Unit::Second,
}
}
#[inline]
pub const fn designator(self, designator: Designator) -> SpanPrinter {
SpanPrinter { designator, ..self }
}
#[inline]
pub const fn spacing(self, spacing: Spacing) -> SpanPrinter {
SpanPrinter { spacing, ..self }
}
#[inline]
pub const fn direction(self, direction: Direction) -> SpanPrinter {
SpanPrinter { direction, ..self }
}
#[inline]
pub const fn fractional(
self,
unit: Option<FractionalUnit>,
) -> SpanPrinter {
SpanPrinter { fractional: unit, ..self }
}
#[inline]
pub const fn comma_after_designator(self, yes: bool) -> SpanPrinter {
SpanPrinter { comma_after_designator: yes, ..self }
}
#[inline]
pub const fn hours_minutes_seconds(self, yes: bool) -> SpanPrinter {
SpanPrinter { hms: yes, ..self }
}
#[inline]
pub const fn padding(self, digits: u8) -> SpanPrinter {
SpanPrinter { padding: Some(digits), ..self }
}
#[inline]
pub const fn precision(self, precision: Option<u8>) -> SpanPrinter {
SpanPrinter { precision, ..self }
}
#[inline]
pub const fn zero_unit(self, unit: Unit) -> SpanPrinter {
SpanPrinter { zero_unit: unit, ..self }
}
#[cfg(any(test, feature = "alloc"))]
pub fn span_to_string(&self, span: &Span) -> alloc::string::String {
let mut buf = alloc::string::String::with_capacity(4);
self.print_span(span, &mut buf).unwrap();
buf
}
#[cfg(any(test, feature = "alloc"))]
pub fn duration_to_string(
&self,
duration: &SignedDuration,
) -> alloc::string::String {
let mut buf = alloc::string::String::with_capacity(4);
self.print_duration(duration, &mut buf).unwrap();
buf
}
pub fn print_span<W: Write>(
&self,
span: &Span,
wtr: W,
) -> Result<(), Error> {
if self.hms {
return self.print_span_hms(span, wtr);
}
self.print_span_designators(span, wtr)
}
pub fn print_duration<W: Write>(
&self,
duration: &SignedDuration,
wtr: W,
) -> Result<(), Error> {
if self.hms {
return self.print_duration_hms(duration, wtr);
}
self.print_duration_designators(duration, wtr)
}
fn print_span_designators<W: Write>(
&self,
span: &Span,
mut wtr: W,
) -> Result<(), Error> {
let mut wtr =
DesignatorWriter::new(self, &mut wtr, false, span.signum());
wtr.maybe_write_prefix_sign()?;
match self.fractional {
None => {
self.print_span_designators_non_fraction(span, &mut wtr)?;
}
Some(unit) => {
self.print_span_designators_fractional(span, unit, &mut wtr)?;
}
}
wtr.maybe_write_zero()?;
wtr.maybe_write_suffix_sign()?;
Ok(())
}
fn print_span_designators_non_fraction<'p, 'w, W: Write>(
&self,
span: &Span,
wtr: &mut DesignatorWriter<'p, 'w, W>,
) -> Result<(), Error> {
let span = span.abs();
if span.get_years() != 0 {
wtr.write(Unit::Year, span.get_years())?;
}
if span.get_months() != 0 {
wtr.write(Unit::Month, span.get_months())?;
}
if span.get_weeks() != 0 {
wtr.write(Unit::Week, span.get_weeks())?;
}
if span.get_days() != 0 {
wtr.write(Unit::Day, span.get_days())?;
}
if span.get_hours() != 0 {
wtr.write(Unit::Hour, span.get_hours())?;
}
if span.get_minutes() != 0 {
wtr.write(Unit::Minute, span.get_minutes())?;
}
if span.get_seconds() != 0 {
wtr.write(Unit::Second, span.get_seconds())?;
}
if span.get_milliseconds() != 0 {
wtr.write(Unit::Millisecond, span.get_milliseconds())?;
}
if span.get_microseconds() != 0 {
wtr.write(Unit::Microsecond, span.get_microseconds())?;
}
if span.get_nanoseconds() != 0 {
wtr.write(Unit::Nanosecond, span.get_nanoseconds())?;
}
Ok(())
}
#[inline(never)]
fn print_span_designators_fractional<'p, 'w, W: Write>(
&self,
span: &Span,
unit: FractionalUnit,
wtr: &mut DesignatorWriter<'p, 'w, W>,
) -> Result<(), Error> {
let split_at = Unit::from(unit).next().unwrap();
let non_fractional = span.without_lower(split_at);
let fractional = span.only_lower(split_at);
self.print_span_designators_non_fraction(&non_fractional, wtr)?;
wtr.write_fractional_duration(
unit,
&fractional.to_jiff_duration_invariant(),
)?;
Ok(())
}
fn print_span_hms<W: Write>(
&self,
span: &Span,
mut wtr: W,
) -> Result<(), Error> {
let span_cal = span.only_calendar();
let mut span_time = span.only_time();
let has_cal = !span_cal.is_zero();
let mut wtr =
DesignatorWriter::new(self, &mut wtr, has_cal, span.signum());
wtr.maybe_write_prefix_sign()?;
if has_cal {
self.print_span_designators_non_fraction(&span_cal, &mut wtr)?;
wtr.finish_preceding()?;
if matches!(self.spacing, Spacing::None) {
wtr.wtr.write_str(" ")?;
}
}
span_time = span_time.abs();
let fmtint =
DecimalFormatter::new().padding(self.padding.unwrap_or(2));
let fmtfraction = FractionalFormatter::new().precision(self.precision);
wtr.wtr.write_int(&fmtint, span_time.get_hours_ranged().get())?;
wtr.wtr.write_str(":")?;
wtr.wtr.write_int(&fmtint, span_time.get_minutes_ranged().get())?;
wtr.wtr.write_str(":")?;
let fp = FractionalPrinter::from_span(
&span_time.only_lower(Unit::Minute),
FractionalUnit::Second,
fmtint,
fmtfraction,
);
fp.print(&mut wtr.wtr)?;
wtr.maybe_write_suffix_sign()?;
Ok(())
}
fn print_duration_designators<W: Write>(
&self,
dur: &SignedDuration,
mut wtr: W,
) -> Result<(), Error> {
let mut wtr =
DesignatorWriter::new(self, &mut wtr, false, dur.signum());
wtr.maybe_write_prefix_sign()?;
match self.fractional {
None => {
let mut secs = dur.as_secs();
wtr.write(Unit::Hour, (secs / SECS_PER_HOUR).abs())?;
secs %= MINS_PER_HOUR * SECS_PER_MIN;
wtr.write(Unit::Minute, (secs / SECS_PER_MIN).abs())?;
wtr.write(Unit::Second, (secs % SECS_PER_MIN).abs())?;
let mut nanos = dur.subsec_nanos();
wtr.write(Unit::Millisecond, (nanos / NANOS_PER_MILLI).abs())?;
nanos %= NANOS_PER_MILLI;
wtr.write(Unit::Microsecond, (nanos / NANOS_PER_MICRO).abs())?;
wtr.write(Unit::Nanosecond, (nanos % NANOS_PER_MICRO).abs())?;
}
Some(FractionalUnit::Hour) => {
wtr.write_fractional_duration(FractionalUnit::Hour, dur)?;
}
Some(FractionalUnit::Minute) => {
let mut secs = dur.as_secs();
wtr.write(Unit::Hour, (secs / SECS_PER_HOUR).abs())?;
secs %= MINS_PER_HOUR * SECS_PER_MIN;
let leftovers = SignedDuration::new(secs, dur.subsec_nanos());
wtr.write_fractional_duration(
FractionalUnit::Minute,
&leftovers,
)?;
}
Some(FractionalUnit::Second) => {
let mut secs = dur.as_secs();
wtr.write(Unit::Hour, (secs / SECS_PER_HOUR).abs())?;
secs %= MINS_PER_HOUR * SECS_PER_MIN;
wtr.write(Unit::Minute, (secs / SECS_PER_MIN).abs())?;
secs %= SECS_PER_MIN;
let leftovers =
SignedDuration::new(secs, dur.subsec_nanos()).abs();
wtr.write_fractional_duration(
FractionalUnit::Second,
&leftovers,
)?;
}
Some(FractionalUnit::Millisecond) => {
let mut secs = dur.as_secs();
wtr.write(Unit::Hour, (secs / SECS_PER_HOUR).abs())?;
secs %= MINS_PER_HOUR * SECS_PER_MIN;
wtr.write(Unit::Minute, (secs / SECS_PER_MIN).abs())?;
wtr.write(Unit::Second, (secs % SECS_PER_MIN).abs())?;
let leftovers =
SignedDuration::new(0, dur.subsec_nanos().abs());
wtr.write_fractional_duration(
FractionalUnit::Millisecond,
&leftovers,
)?;
}
Some(FractionalUnit::Microsecond) => {
let mut secs = dur.as_secs();
wtr.write(Unit::Hour, (secs / SECS_PER_HOUR).abs())?;
secs %= MINS_PER_HOUR * SECS_PER_MIN;
wtr.write(Unit::Minute, (secs / SECS_PER_MIN).abs())?;
wtr.write(Unit::Second, (secs % SECS_PER_MIN).abs())?;
let mut nanos = dur.subsec_nanos();
wtr.write(Unit::Millisecond, (nanos / NANOS_PER_MILLI).abs())?;
nanos %= NANOS_PER_MILLI;
let leftovers = SignedDuration::new(0, nanos.abs());
wtr.write_fractional_duration(
FractionalUnit::Microsecond,
&leftovers,
)?;
}
}
wtr.maybe_write_zero()?;
wtr.maybe_write_suffix_sign()?;
Ok(())
}
fn print_duration_hms<W: Write>(
&self,
dur: &SignedDuration,
mut wtr: W,
) -> Result<(), Error> {
let fmtint =
DecimalFormatter::new().padding(self.padding.unwrap_or(2));
let fmtfraction = FractionalFormatter::new().precision(self.precision);
if dur.is_negative() {
if !matches!(self.direction, Direction::Suffix) {
wtr.write_str("-")?;
}
} else if let Direction::ForceSign = self.direction {
wtr.write_str("+")?;
}
let mut secs = dur.as_secs();
let hours = (secs / (MINS_PER_HOUR * SECS_PER_MIN)).abs();
secs %= MINS_PER_HOUR * SECS_PER_MIN;
let minutes = (secs / SECS_PER_MIN).abs();
secs = (secs % SECS_PER_MIN).abs();
wtr.write_int(&fmtint, hours)?;
wtr.write_str(":")?;
wtr.write_int(&fmtint, minutes)?;
wtr.write_str(":")?;
let fp = FractionalPrinter::from_duration(
&SignedDuration::new(secs, dur.subsec_nanos().abs()),
FractionalUnit::Second,
fmtint,
fmtfraction,
);
fp.print(&mut wtr)?;
if dur.is_negative() {
if matches!(self.direction, Direction::Suffix) {
wtr.write_str(" ago")?;
}
}
Ok(())
}
}
impl Default for SpanPrinter {
fn default() -> SpanPrinter {
SpanPrinter::new()
}
}
#[derive(Debug)]
struct Designators {
singular: &'static [&'static str],
plural: &'static [&'static str],
}
impl Designators {
const VERBOSE_SINGULAR: &'static [&'static str] = &[
"nanosecond",
"microsecond",
"millisecond",
"second",
"minute",
"hour",
"day",
"week",
"month",
"year",
];
const VERBOSE_PLURAL: &'static [&'static str] = &[
"nanoseconds",
"microseconds",
"milliseconds",
"seconds",
"minutes",
"hours",
"days",
"weeks",
"months",
"years",
];
const SHORT_SINGULAR: &'static [&'static str] =
&["nsec", "µsec", "msec", "sec", "min", "hr", "day", "wk", "mo", "yr"];
const SHORT_PLURAL: &'static [&'static str] = &[
"nsecs", "µsecs", "msecs", "secs", "mins", "hrs", "days", "wks",
"mos", "yrs",
];
const COMPACT: &'static [&'static str] =
&["ns", "µs", "ms", "s", "m", "h", "d", "w", "mo", "y"];
const HUMAN_TIME_SINGULAR: &'static [&'static str] =
&["ns", "us", "ms", "s", "m", "h", "d", "w", "month", "y"];
const HUMAN_TIME_PLURAL: &'static [&'static str] =
&["ns", "us", "ms", "s", "m", "h", "d", "w", "months", "y"];
fn new(config: Designator) -> Designators {
match config {
Designator::Verbose => Designators {
singular: Designators::VERBOSE_SINGULAR,
plural: Designators::VERBOSE_PLURAL,
},
Designator::Short => Designators {
singular: Designators::SHORT_SINGULAR,
plural: Designators::SHORT_PLURAL,
},
Designator::Compact => Designators {
singular: Designators::COMPACT,
plural: Designators::COMPACT,
},
Designator::HumanTime => Designators {
singular: Designators::HUMAN_TIME_SINGULAR,
plural: Designators::HUMAN_TIME_PLURAL,
},
}
}
fn designator(&self, unit: impl Into<Unit>, plural: bool) -> &'static str {
let unit = unit.into();
let index = unit as usize;
if plural {
self.plural[index]
} else {
self.singular[index]
}
}
}
#[derive(Debug)]
struct DesignatorWriter<'p, 'w, W> {
printer: &'p SpanPrinter,
wtr: &'w mut W,
desig: Designators,
sign: Option<DirectionSign>,
fmtint: DecimalFormatter,
fmtfraction: FractionalFormatter,
written_non_zero_unit: bool,
}
impl<'p, 'w, W: Write> DesignatorWriter<'p, 'w, W> {
fn new(
printer: &'p SpanPrinter,
wtr: &'w mut W,
has_calendar: bool,
signum: i8,
) -> DesignatorWriter<'p, 'w, W> {
let desig = Designators::new(printer.designator);
let sign = printer.direction.sign(printer, has_calendar, signum);
let fmtint =
DecimalFormatter::new().padding(printer.padding.unwrap_or(0));
let fmtfraction =
FractionalFormatter::new().precision(printer.precision);
DesignatorWriter {
printer,
wtr,
desig,
sign,
fmtint,
fmtfraction,
written_non_zero_unit: false,
}
}
fn maybe_write_prefix_sign(&mut self) -> Result<(), Error> {
if let Some(DirectionSign::Prefix(sign)) = self.sign {
self.wtr.write_str(sign)?;
}
Ok(())
}
fn maybe_write_suffix_sign(&mut self) -> Result<(), Error> {
if let Some(DirectionSign::Suffix(sign)) = self.sign {
self.wtr.write_str(sign)?;
}
Ok(())
}
fn maybe_write_zero(&mut self) -> Result<(), Error> {
if self.written_non_zero_unit {
return Ok(());
}
let unit = self
.printer
.fractional
.map(Unit::from)
.unwrap_or(self.printer.zero_unit);
self.wtr.write_int(&self.fmtint, 0)?;
self.wtr
.write_str(self.printer.spacing.between_units_and_designators())?;
self.wtr.write_str(self.desig.designator(unit, true))?;
Ok(())
}
fn write(
&mut self,
unit: Unit,
value: impl Into<i64>,
) -> Result<(), Error> {
let value = value.into();
if value == 0 {
return Ok(());
}
self.finish_preceding()?;
self.written_non_zero_unit = true;
self.wtr.write_int(&self.fmtint, value)?;
self.wtr
.write_str(self.printer.spacing.between_units_and_designators())?;
self.wtr.write_str(self.desig.designator(unit, value != 1))?;
Ok(())
}
fn write_fractional_duration(
&mut self,
unit: FractionalUnit,
duration: &SignedDuration,
) -> Result<(), Error> {
let fp = FractionalPrinter::from_duration(
duration,
unit,
self.fmtint,
self.fmtfraction,
);
if !fp.must_write_digits() {
return Ok(());
}
self.finish_preceding()?;
self.written_non_zero_unit = true;
fp.print(&mut *self.wtr)?;
self.wtr
.write_str(self.printer.spacing.between_units_and_designators())?;
self.wtr.write_str(self.desig.designator(unit, fp.is_plural()))?;
Ok(())
}
fn finish_preceding(&mut self) -> Result<(), Error> {
if self.written_non_zero_unit {
if self.printer.comma_after_designator {
self.wtr.write_str(",")?;
}
self.wtr.write_str(self.printer.spacing.between_units())?;
}
Ok(())
}
}
struct FractionalPrinter {
integer: i64,
fraction: i64,
fmtint: DecimalFormatter,
fmtfraction: FractionalFormatter,
}
impl FractionalPrinter {
fn from_span(
span: &Span,
unit: FractionalUnit,
fmtint: DecimalFormatter,
fmtfraction: FractionalFormatter,
) -> FractionalPrinter {
debug_assert!(span.largest_unit() <= Unit::from(unit));
let dur = span.to_jiff_duration_invariant();
FractionalPrinter::from_duration(&dur, unit, fmtint, fmtfraction)
}
fn from_duration(
dur: &SignedDuration,
unit: FractionalUnit,
fmtint: DecimalFormatter,
fmtfraction: FractionalFormatter,
) -> FractionalPrinter {
match unit {
FractionalUnit::Hour => {
let integer = (dur.as_secs() / SECS_PER_HOUR).abs();
let fraction = dur.as_nanos() % NANOS_PER_HOUR;
debug_assert!(fraction <= i128::from(i64::MAX));
let mut fraction = i64::try_from(fraction).unwrap();
fraction /= SECS_PER_HOUR;
fraction = fraction.abs();
FractionalPrinter { integer, fraction, fmtint, fmtfraction }
}
FractionalUnit::Minute => {
let integer = (dur.as_secs() / SECS_PER_MIN).abs();
let fraction = dur.as_nanos() % NANOS_PER_MIN;
debug_assert!(fraction <= i128::from(i64::MAX));
let mut fraction = i64::try_from(fraction).unwrap();
fraction /= SECS_PER_MIN;
fraction = fraction.abs();
FractionalPrinter { integer, fraction, fmtint, fmtfraction }
}
FractionalUnit::Second => {
let integer = dur.as_secs();
let fraction = i64::from(dur.subsec_nanos());
FractionalPrinter { integer, fraction, fmtint, fmtfraction }
}
FractionalUnit::Millisecond => {
let integer = i64::try_from(dur.as_millis()).unwrap();
let fraction =
i64::from((dur.subsec_nanos() % NANOS_PER_MILLI) * 1_000);
FractionalPrinter { integer, fraction, fmtint, fmtfraction }
}
FractionalUnit::Microsecond => {
let integer = i64::try_from(dur.as_micros()).unwrap();
let fraction = i64::from(
(dur.subsec_nanos() % NANOS_PER_MICRO) * 1_000_000,
);
FractionalPrinter { integer, fraction, fmtint, fmtfraction }
}
}
}
fn is_zero(&self) -> bool {
self.integer == 0 && self.fraction == 0
}
fn is_plural(&self) -> bool {
self.integer != 1
|| (self.fraction != 0
&& !self.fmtfraction.has_zero_fixed_precision())
}
fn must_write_digits(&self) -> bool {
!self.is_zero() || self.fmtfraction.has_non_zero_fixed_precision()
}
fn print<W: Write>(&self, mut wtr: W) -> Result<(), Error> {
wtr.write_int(&self.fmtint, self.integer)?;
if self.fmtfraction.will_write_digits(self.fraction) {
wtr.write_str(".")?;
wtr.write_fraction(&self.fmtfraction, self.fraction)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::ToSpan;
use super::*;
#[test]
fn print_span_designator_default() {
let printer = || SpanPrinter::new();
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(p(1.second()), @"1s");
insta::assert_snapshot!(p(2.seconds()), @"2s");
insta::assert_snapshot!(p(10.seconds()), @"10s");
insta::assert_snapshot!(p(1.minute().seconds(40)), @"1m 40s");
insta::assert_snapshot!(p(1.minute()), @"1m");
insta::assert_snapshot!(p(2.minutes()), @"2m");
insta::assert_snapshot!(p(10.minutes()), @"10m");
insta::assert_snapshot!(p(1.hour().minutes(40)), @"1h 40m");
insta::assert_snapshot!(p(1.hour()), @"1h");
insta::assert_snapshot!(p(2.hours()), @"2h");
insta::assert_snapshot!(p(10.hours()), @"10h");
insta::assert_snapshot!(p(100.hours()), @"100h");
insta::assert_snapshot!(
p(1.hour().minutes(1).seconds(1)),
@"1h 1m 1s",
);
insta::assert_snapshot!(
p(2.hours().minutes(2).seconds(2)),
@"2h 2m 2s",
);
insta::assert_snapshot!(
p(10.hours().minutes(10).seconds(10)),
@"10h 10m 10s",
);
insta::assert_snapshot!(
p(100.hours().minutes(100).seconds(100)),
@"100h 100m 100s",
);
insta::assert_snapshot!(p(-1.hour()), @"1h ago");
insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1h 30s ago");
insta::assert_snapshot!(
p(1.second().milliseconds(2000)),
@"1s 2000ms",
);
}
#[test]
fn print_span_designator_verbose() {
let printer = || SpanPrinter::new().designator(Designator::Verbose);
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(p(1.second()), @"1second");
insta::assert_snapshot!(p(2.seconds()), @"2seconds");
insta::assert_snapshot!(p(10.seconds()), @"10seconds");
insta::assert_snapshot!(p(1.minute().seconds(40)), @"1minute 40seconds");
insta::assert_snapshot!(p(1.minute()), @"1minute");
insta::assert_snapshot!(p(2.minutes()), @"2minutes");
insta::assert_snapshot!(p(10.minutes()), @"10minutes");
insta::assert_snapshot!(p(1.hour().minutes(40)), @"1hour 40minutes");
insta::assert_snapshot!(p(1.hour()), @"1hour");
insta::assert_snapshot!(p(2.hours()), @"2hours");
insta::assert_snapshot!(p(10.hours()), @"10hours");
insta::assert_snapshot!(p(100.hours()), @"100hours");
insta::assert_snapshot!(
p(1.hour().minutes(1).seconds(1)),
@"1hour 1minute 1second",
);
insta::assert_snapshot!(
p(2.hours().minutes(2).seconds(2)),
@"2hours 2minutes 2seconds",
);
insta::assert_snapshot!(
p(10.hours().minutes(10).seconds(10)),
@"10hours 10minutes 10seconds",
);
insta::assert_snapshot!(
p(100.hours().minutes(100).seconds(100)),
@"100hours 100minutes 100seconds",
);
insta::assert_snapshot!(p(-1.hour()), @"1hour ago");
insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1hour 30seconds ago");
}
#[test]
fn print_span_designator_short() {
let printer = || SpanPrinter::new().designator(Designator::Short);
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(p(1.second()), @"1sec");
insta::assert_snapshot!(p(2.seconds()), @"2secs");
insta::assert_snapshot!(p(10.seconds()), @"10secs");
insta::assert_snapshot!(p(1.minute().seconds(40)), @"1min 40secs");
insta::assert_snapshot!(p(1.minute()), @"1min");
insta::assert_snapshot!(p(2.minutes()), @"2mins");
insta::assert_snapshot!(p(10.minutes()), @"10mins");
insta::assert_snapshot!(p(1.hour().minutes(40)), @"1hr 40mins");
insta::assert_snapshot!(p(1.hour()), @"1hr");
insta::assert_snapshot!(p(2.hours()), @"2hrs");
insta::assert_snapshot!(p(10.hours()), @"10hrs");
insta::assert_snapshot!(p(100.hours()), @"100hrs");
insta::assert_snapshot!(
p(1.hour().minutes(1).seconds(1)),
@"1hr 1min 1sec",
);
insta::assert_snapshot!(
p(2.hours().minutes(2).seconds(2)),
@"2hrs 2mins 2secs",
);
insta::assert_snapshot!(
p(10.hours().minutes(10).seconds(10)),
@"10hrs 10mins 10secs",
);
insta::assert_snapshot!(
p(100.hours().minutes(100).seconds(100)),
@"100hrs 100mins 100secs",
);
insta::assert_snapshot!(p(-1.hour()), @"1hr ago");
insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1hr 30secs ago");
}
#[test]
fn print_span_designator_compact() {
let printer = || SpanPrinter::new().designator(Designator::Compact);
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(p(1.second()), @"1s");
insta::assert_snapshot!(p(2.seconds()), @"2s");
insta::assert_snapshot!(p(10.seconds()), @"10s");
insta::assert_snapshot!(p(1.minute().seconds(40)), @"1m 40s");
insta::assert_snapshot!(p(1.minute()), @"1m");
insta::assert_snapshot!(p(2.minutes()), @"2m");
insta::assert_snapshot!(p(10.minutes()), @"10m");
insta::assert_snapshot!(p(1.hour().minutes(40)), @"1h 40m");
insta::assert_snapshot!(p(1.hour()), @"1h");
insta::assert_snapshot!(p(2.hours()), @"2h");
insta::assert_snapshot!(p(10.hours()), @"10h");
insta::assert_snapshot!(p(100.hours()), @"100h");
insta::assert_snapshot!(
p(1.hour().minutes(1).seconds(1)),
@"1h 1m 1s",
);
insta::assert_snapshot!(
p(2.hours().minutes(2).seconds(2)),
@"2h 2m 2s",
);
insta::assert_snapshot!(
p(10.hours().minutes(10).seconds(10)),
@"10h 10m 10s",
);
insta::assert_snapshot!(
p(100.hours().minutes(100).seconds(100)),
@"100h 100m 100s",
);
insta::assert_snapshot!(p(-1.hour()), @"1h ago");
insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1h 30s ago");
}
#[test]
fn print_span_designator_direction_force() {
let printer = || SpanPrinter::new().direction(Direction::ForceSign);
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(p(1.second()), @"+1s");
insta::assert_snapshot!(p(2.seconds()), @"+2s");
insta::assert_snapshot!(p(10.seconds()), @"+10s");
insta::assert_snapshot!(p(1.minute().seconds(40)), @"+1m 40s");
insta::assert_snapshot!(p(1.minute()), @"+1m");
insta::assert_snapshot!(p(2.minutes()), @"+2m");
insta::assert_snapshot!(p(10.minutes()), @"+10m");
insta::assert_snapshot!(p(1.hour().minutes(40)), @"+1h 40m");
insta::assert_snapshot!(p(1.hour()), @"+1h");
insta::assert_snapshot!(p(2.hours()), @"+2h");
insta::assert_snapshot!(p(10.hours()), @"+10h");
insta::assert_snapshot!(p(100.hours()), @"+100h");
insta::assert_snapshot!(
p(1.hour().minutes(1).seconds(1)),
@"+1h 1m 1s",
);
insta::assert_snapshot!(
p(2.hours().minutes(2).seconds(2)),
@"+2h 2m 2s",
);
insta::assert_snapshot!(
p(10.hours().minutes(10).seconds(10)),
@"+10h 10m 10s",
);
insta::assert_snapshot!(
p(100.hours().minutes(100).seconds(100)),
@"+100h 100m 100s",
);
insta::assert_snapshot!(p(-1.hour()), @"-1h");
insta::assert_snapshot!(p(-1.hour().seconds(30)), @"-1h 30s");
}
#[test]
fn print_span_designator_padding() {
let printer = || SpanPrinter::new().padding(2);
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(p(1.second()), @"01s");
insta::assert_snapshot!(p(2.seconds()), @"02s");
insta::assert_snapshot!(p(10.seconds()), @"10s");
insta::assert_snapshot!(p(1.minute().seconds(40)), @"01m 40s");
insta::assert_snapshot!(p(1.minute()), @"01m");
insta::assert_snapshot!(p(2.minutes()), @"02m");
insta::assert_snapshot!(p(10.minutes()), @"10m");
insta::assert_snapshot!(p(1.hour().minutes(40)), @"01h 40m");
insta::assert_snapshot!(p(1.hour()), @"01h");
insta::assert_snapshot!(p(2.hours()), @"02h");
insta::assert_snapshot!(p(10.hours()), @"10h");
insta::assert_snapshot!(p(100.hours()), @"100h");
insta::assert_snapshot!(
p(1.hour().minutes(1).seconds(1)),
@"01h 01m 01s",
);
insta::assert_snapshot!(
p(2.hours().minutes(2).seconds(2)),
@"02h 02m 02s",
);
insta::assert_snapshot!(
p(10.hours().minutes(10).seconds(10)),
@"10h 10m 10s",
);
insta::assert_snapshot!(
p(100.hours().minutes(100).seconds(100)),
@"100h 100m 100s",
);
insta::assert_snapshot!(p(-1.hour()), @"01h ago");
insta::assert_snapshot!(p(-1.hour().seconds(30)), @"01h 30s ago");
}
#[test]
fn print_span_designator_spacing_none() {
let printer = || SpanPrinter::new().spacing(Spacing::None);
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(p(1.second()), @"1s");
insta::assert_snapshot!(p(2.seconds()), @"2s");
insta::assert_snapshot!(p(10.seconds()), @"10s");
insta::assert_snapshot!(p(1.minute().seconds(40)), @"1m40s");
insta::assert_snapshot!(p(1.minute()), @"1m");
insta::assert_snapshot!(p(2.minutes()), @"2m");
insta::assert_snapshot!(p(10.minutes()), @"10m");
insta::assert_snapshot!(p(1.hour().minutes(40)), @"1h40m");
insta::assert_snapshot!(p(1.hour()), @"1h");
insta::assert_snapshot!(p(2.hours()), @"2h");
insta::assert_snapshot!(p(10.hours()), @"10h");
insta::assert_snapshot!(p(100.hours()), @"100h");
insta::assert_snapshot!(
p(1.hour().minutes(1).seconds(1)),
@"1h1m1s",
);
insta::assert_snapshot!(
p(2.hours().minutes(2).seconds(2)),
@"2h2m2s",
);
insta::assert_snapshot!(
p(10.hours().minutes(10).seconds(10)),
@"10h10m10s",
);
insta::assert_snapshot!(
p(100.hours().minutes(100).seconds(100)),
@"100h100m100s",
);
insta::assert_snapshot!(p(-1.hour()), @"-1h");
insta::assert_snapshot!(p(-1.hour().seconds(30)), @"-1h30s");
}
#[test]
fn print_span_designator_spacing_more() {
let printer =
|| SpanPrinter::new().spacing(Spacing::BetweenUnitsAndDesignators);
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(p(1.second()), @"1 s");
insta::assert_snapshot!(p(2.seconds()), @"2 s");
insta::assert_snapshot!(p(10.seconds()), @"10 s");
insta::assert_snapshot!(p(1.minute().seconds(40)), @"1 m 40 s");
insta::assert_snapshot!(p(1.minute()), @"1 m");
insta::assert_snapshot!(p(2.minutes()), @"2 m");
insta::assert_snapshot!(p(10.minutes()), @"10 m");
insta::assert_snapshot!(p(1.hour().minutes(40)), @"1 h 40 m");
insta::assert_snapshot!(p(1.hour()), @"1 h");
insta::assert_snapshot!(p(2.hours()), @"2 h");
insta::assert_snapshot!(p(10.hours()), @"10 h");
insta::assert_snapshot!(p(100.hours()), @"100 h");
insta::assert_snapshot!(
p(1.hour().minutes(1).seconds(1)),
@"1 h 1 m 1 s",
);
insta::assert_snapshot!(
p(2.hours().minutes(2).seconds(2)),
@"2 h 2 m 2 s",
);
insta::assert_snapshot!(
p(10.hours().minutes(10).seconds(10)),
@"10 h 10 m 10 s",
);
insta::assert_snapshot!(
p(100.hours().minutes(100).seconds(100)),
@"100 h 100 m 100 s",
);
insta::assert_snapshot!(p(-1.hour()), @"1 h ago");
insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1 h 30 s ago");
}
#[test]
fn print_span_designator_spacing_comma() {
let printer = || {
SpanPrinter::new()
.comma_after_designator(true)
.spacing(Spacing::BetweenUnitsAndDesignators)
};
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(p(1.second()), @"1 s");
insta::assert_snapshot!(p(2.seconds()), @"2 s");
insta::assert_snapshot!(p(10.seconds()), @"10 s");
insta::assert_snapshot!(p(1.minute().seconds(40)), @"1 m, 40 s");
insta::assert_snapshot!(p(1.minute()), @"1 m");
insta::assert_snapshot!(p(2.minutes()), @"2 m");
insta::assert_snapshot!(p(10.minutes()), @"10 m");
insta::assert_snapshot!(p(1.hour().minutes(40)), @"1 h, 40 m");
insta::assert_snapshot!(p(1.hour()), @"1 h");
insta::assert_snapshot!(p(2.hours()), @"2 h");
insta::assert_snapshot!(p(10.hours()), @"10 h");
insta::assert_snapshot!(p(100.hours()), @"100 h");
insta::assert_snapshot!(
p(1.hour().minutes(1).seconds(1)),
@"1 h, 1 m, 1 s",
);
insta::assert_snapshot!(
p(2.hours().minutes(2).seconds(2)),
@"2 h, 2 m, 2 s",
);
insta::assert_snapshot!(
p(10.hours().minutes(10).seconds(10)),
@"10 h, 10 m, 10 s",
);
insta::assert_snapshot!(
p(100.hours().minutes(100).seconds(100)),
@"100 h, 100 m, 100 s",
);
insta::assert_snapshot!(p(-1.hour()), @"1 h ago");
insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1 h, 30 s ago");
}
#[test]
fn print_span_designator_fractional_hour() {
let printer =
|| SpanPrinter::new().fractional(Some(FractionalUnit::Hour));
let p = |span| printer().span_to_string(&span);
let pp = |precision, span| {
printer().precision(Some(precision)).span_to_string(&span)
};
insta::assert_snapshot!(p(1.hour()), @"1h");
insta::assert_snapshot!(pp(0, 1.hour()), @"1h");
insta::assert_snapshot!(pp(1, 1.hour()), @"1.0h");
insta::assert_snapshot!(pp(2, 1.hour()), @"1.00h");
insta::assert_snapshot!(p(1.hour().minutes(30)), @"1.5h");
insta::assert_snapshot!(pp(0, 1.hour().minutes(30)), @"1h");
insta::assert_snapshot!(pp(1, 1.hour().minutes(30)), @"1.5h");
insta::assert_snapshot!(pp(2, 1.hour().minutes(30)), @"1.50h");
insta::assert_snapshot!(p(1.hour().minutes(3)), @"1.05h");
insta::assert_snapshot!(p(1.hour().minutes(3).nanoseconds(1)), @"1.05h");
insta::assert_snapshot!(p(1.second()), @"0.000277777h");
insta::assert_snapshot!(p(1.second().nanoseconds(1)), @"0.000277777h");
insta::assert_snapshot!(p(0.seconds()), @"0h");
insta::assert_snapshot!(p(1.nanosecond()), @"0h");
}
#[test]
fn print_span_designator_fractional_minute() {
let printer =
|| SpanPrinter::new().fractional(Some(FractionalUnit::Minute));
let p = |span| printer().span_to_string(&span);
let pp = |precision, span| {
printer().precision(Some(precision)).span_to_string(&span)
};
insta::assert_snapshot!(p(1.hour()), @"1h");
insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
insta::assert_snapshot!(p(1.minute()), @"1m");
insta::assert_snapshot!(pp(0, 1.minute()), @"1m");
insta::assert_snapshot!(pp(1, 1.minute()), @"1.0m");
insta::assert_snapshot!(pp(2, 1.minute()), @"1.00m");
insta::assert_snapshot!(p(1.minute().seconds(30)), @"1.5m");
insta::assert_snapshot!(pp(0, 1.minute().seconds(30)), @"1m");
insta::assert_snapshot!(pp(1, 1.minute().seconds(30)), @"1.5m");
insta::assert_snapshot!(pp(2, 1.minute().seconds(30)), @"1.50m");
insta::assert_snapshot!(p(1.hour().nanoseconds(1)), @"1h");
insta::assert_snapshot!(p(1.minute().seconds(3)), @"1.05m");
insta::assert_snapshot!(p(1.minute().seconds(3).nanoseconds(1)), @"1.05m");
insta::assert_snapshot!(p(1.second()), @"0.016666666m");
insta::assert_snapshot!(p(1.second().nanoseconds(1)), @"0.016666666m");
insta::assert_snapshot!(p(0.seconds()), @"0m");
insta::assert_snapshot!(p(1.nanosecond()), @"0m");
}
#[test]
fn print_span_designator_fractional_second() {
let printer =
|| SpanPrinter::new().fractional(Some(FractionalUnit::Second));
let p = |span| printer().span_to_string(&span);
let pp = |precision, span| {
printer().precision(Some(precision)).span_to_string(&span)
};
insta::assert_snapshot!(p(1.hour()), @"1h");
insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
insta::assert_snapshot!(p(1.second()), @"1s");
insta::assert_snapshot!(pp(0, 1.second()), @"1s");
insta::assert_snapshot!(pp(1, 1.second()), @"1.0s");
insta::assert_snapshot!(pp(2, 1.second()), @"1.00s");
insta::assert_snapshot!(p(1.second().milliseconds(500)), @"1.5s");
insta::assert_snapshot!(pp(0, 1.second().milliseconds(500)), @"1s");
insta::assert_snapshot!(pp(1, 1.second().milliseconds(500)), @"1.5s");
insta::assert_snapshot!(pp(2, 1.second().milliseconds(500)), @"1.50s");
insta::assert_snapshot!(p(1.second().nanoseconds(1)), @"1.000000001s");
insta::assert_snapshot!(p(1.nanosecond()), @"0.000000001s");
insta::assert_snapshot!(p(0.seconds()), @"0s");
insta::assert_snapshot!(p(1.second().milliseconds(2000)), @"3s");
}
#[test]
fn print_span_designator_fractional_millisecond() {
let printer = || {
SpanPrinter::new().fractional(Some(FractionalUnit::Millisecond))
};
let p = |span| printer().span_to_string(&span);
let pp = |precision, span| {
printer().precision(Some(precision)).span_to_string(&span)
};
insta::assert_snapshot!(p(1.hour()), @"1h");
insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
insta::assert_snapshot!(
p(1.hour().minutes(30).seconds(10)),
@"1h 30m 10s",
);
insta::assert_snapshot!(p(1.second()), @"1s");
insta::assert_snapshot!(pp(0, 1.second()), @"1s");
insta::assert_snapshot!(pp(1, 1.second()), @"1s 0.0ms");
insta::assert_snapshot!(pp(2, 1.second()), @"1s 0.00ms");
insta::assert_snapshot!(p(1.second().milliseconds(500)), @"1s 500ms");
insta::assert_snapshot!(
pp(0, 1.second().milliseconds(1).microseconds(500)),
@"1s 1ms",
);
insta::assert_snapshot!(
pp(1, 1.second().milliseconds(1).microseconds(500)),
@"1s 1.5ms",
);
insta::assert_snapshot!(
pp(2, 1.second().milliseconds(1).microseconds(500)),
@"1s 1.50ms",
);
insta::assert_snapshot!(p(1.millisecond().nanoseconds(1)), @"1.000001ms");
insta::assert_snapshot!(p(1.nanosecond()), @"0.000001ms");
insta::assert_snapshot!(p(0.seconds()), @"0ms");
}
#[test]
fn print_span_designator_fractional_microsecond() {
let printer = || {
SpanPrinter::new().fractional(Some(FractionalUnit::Microsecond))
};
let p = |span| printer().span_to_string(&span);
let pp = |precision, span| {
printer().precision(Some(precision)).span_to_string(&span)
};
insta::assert_snapshot!(p(1.hour()), @"1h");
insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
insta::assert_snapshot!(
p(1.hour().minutes(30).seconds(10)),
@"1h 30m 10s",
);
insta::assert_snapshot!(p(1.second()), @"1s");
insta::assert_snapshot!(pp(0, 1.second()), @"1s");
insta::assert_snapshot!(pp(1, 1.second()), @"1s 0.0µs");
insta::assert_snapshot!(pp(2, 1.second()), @"1s 0.00µs");
insta::assert_snapshot!(p(1.second().milliseconds(500)), @"1s 500ms");
insta::assert_snapshot!(
pp(0, 1.second().milliseconds(1).microseconds(500)),
@"1s 1ms 500µs",
);
insta::assert_snapshot!(
pp(1, 1.second().milliseconds(1).microseconds(500)),
@"1s 1ms 500.0µs",
);
insta::assert_snapshot!(
pp(2, 1.second().milliseconds(1).microseconds(500)),
@"1s 1ms 500.00µs",
);
insta::assert_snapshot!(
p(1.millisecond().nanoseconds(1)),
@"1ms 0.001µs",
);
insta::assert_snapshot!(p(1.nanosecond()), @"0.001µs");
insta::assert_snapshot!(p(0.second()), @"0µs");
}
#[test]
fn print_duration_designator_default() {
let printer = || SpanPrinter::new();
let p = |secs| {
printer().duration_to_string(&SignedDuration::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",
);
insta::assert_snapshot!(p(-1 * 60 * 60), @"1h ago");
insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1h 30s ago");
}
#[test]
fn print_duration_designator_verbose() {
let printer = || SpanPrinter::new().designator(Designator::Verbose);
let p = |secs| {
printer().duration_to_string(&SignedDuration::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",
);
insta::assert_snapshot!(p(-1 * 60 * 60), @"1hour ago");
insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1hour 30seconds ago");
}
#[test]
fn print_duration_designator_short() {
let printer = || SpanPrinter::new().designator(Designator::Short);
let p = |secs| {
printer().duration_to_string(&SignedDuration::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",
);
insta::assert_snapshot!(p(-1 * 60 * 60), @"1hr ago");
insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1hr 30secs ago");
}
#[test]
fn print_duration_designator_compact() {
let printer = || SpanPrinter::new().designator(Designator::Compact);
let p = |secs| {
printer().duration_to_string(&SignedDuration::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",
);
insta::assert_snapshot!(p(-1 * 60 * 60), @"1h ago");
insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1h 30s ago");
}
#[test]
fn print_duration_designator_direction_force() {
let printer = || SpanPrinter::new().direction(Direction::ForceSign);
let p = |secs| {
printer().duration_to_string(&SignedDuration::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",
);
insta::assert_snapshot!(p(-1 * 60 * 60), @"-1h");
insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"-1h 30s");
}
#[test]
fn print_duration_designator_padding() {
let printer = || SpanPrinter::new().padding(2);
let p = |secs| {
printer().duration_to_string(&SignedDuration::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",
);
insta::assert_snapshot!(p(-1 * 60 * 60), @"01h ago");
insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"01h 30s ago");
}
#[test]
fn print_duration_designator_spacing_none() {
let printer = || SpanPrinter::new().spacing(Spacing::None);
let p = |secs| {
printer().duration_to_string(&SignedDuration::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",
);
insta::assert_snapshot!(p(-1 * 60 * 60), @"-1h");
insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"-1h30s");
}
#[test]
fn print_duration_designator_spacing_more() {
let printer =
|| SpanPrinter::new().spacing(Spacing::BetweenUnitsAndDesignators);
let p = |secs| {
printer().duration_to_string(&SignedDuration::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",
);
insta::assert_snapshot!(p(-1 * 60 * 60), @"1 h ago");
insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1 h 30 s ago");
}
#[test]
fn print_duration_designator_spacing_comma() {
let printer = || {
SpanPrinter::new()
.comma_after_designator(true)
.spacing(Spacing::BetweenUnitsAndDesignators)
};
let p = |secs| {
printer().duration_to_string(&SignedDuration::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",
);
insta::assert_snapshot!(p(-1 * 60 * 60), @"1 h ago");
insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1 h, 30 s ago");
}
#[test]
fn print_duration_designator_fractional_hour() {
let printer =
|| SpanPrinter::new().fractional(Some(FractionalUnit::Hour));
let p = |secs, nanos| {
printer().duration_to_string(&SignedDuration::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");
insta::assert_snapshot!(p(1, 1), @"0.000277777h");
insta::assert_snapshot!(p(0, 0), @"0h");
insta::assert_snapshot!(p(0, 1), @"0h");
insta::assert_snapshot!(
printer().duration_to_string(&SignedDuration::MIN),
@"2562047788015215.502499999h ago",
);
}
#[test]
fn print_duration_designator_fractional_minute() {
let printer =
|| SpanPrinter::new().fractional(Some(FractionalUnit::Minute));
let p = |secs, nanos| {
printer().duration_to_string(&SignedDuration::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");
insta::assert_snapshot!(p(1, 1), @"0.016666666m");
insta::assert_snapshot!(p(0, 0), @"0m");
insta::assert_snapshot!(p(0, 1), @"0m");
insta::assert_snapshot!(
printer().duration_to_string(&SignedDuration::MIN),
@"2562047788015215h 30.149999999m ago",
);
}
#[test]
fn print_duration_designator_fractional_second() {
let printer =
|| SpanPrinter::new().fractional(Some(FractionalUnit::Second));
let p = |secs, nanos| {
printer().duration_to_string(&SignedDuration::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");
insta::assert_snapshot!(
printer().duration_to_string(&SignedDuration::MIN),
@"2562047788015215h 30m 8.999999999s ago",
);
}
#[test]
fn print_duration_designator_fractional_millisecond() {
let printer = || {
SpanPrinter::new().fractional(Some(FractionalUnit::Millisecond))
};
let p = |secs, nanos| {
printer().duration_to_string(&SignedDuration::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");
insta::assert_snapshot!(
printer().duration_to_string(&SignedDuration::MIN),
@"2562047788015215h 30m 8s 999.999999ms ago",
);
}
#[test]
fn print_duration_designator_fractional_microsecond() {
let printer = || {
SpanPrinter::new().fractional(Some(FractionalUnit::Microsecond))
};
let p = |secs, nanos| {
printer().duration_to_string(&SignedDuration::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.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");
insta::assert_snapshot!(
printer().duration_to_string(&SignedDuration::MIN),
@"2562047788015215h 30m 8s 999ms 999.999µs ago",
);
}
#[test]
fn print_span_hms() {
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(p(1.second()), @"00:00:01");
insta::assert_snapshot!(p(2.seconds()), @"00:00:02");
insta::assert_snapshot!(p(10.seconds()), @"00:00:10");
insta::assert_snapshot!(p(100.seconds()), @"00:00:100");
insta::assert_snapshot!(p(1.minute()), @"00:01:00");
insta::assert_snapshot!(p(2.minutes()), @"00:02:00");
insta::assert_snapshot!(p(10.minutes()), @"00:10:00");
insta::assert_snapshot!(p(100.minutes()), @"00:100:00");
insta::assert_snapshot!(p(1.hour()), @"01:00:00");
insta::assert_snapshot!(p(2.hours()), @"02:00:00");
insta::assert_snapshot!(p(10.hours()), @"10:00:00");
insta::assert_snapshot!(p(100.hours()), @"100:00:00");
insta::assert_snapshot!(
p(1.hour().minutes(1).seconds(1)),
@"01:01:01",
);
insta::assert_snapshot!(
p(2.hours().minutes(2).seconds(2)),
@"02:02:02",
);
insta::assert_snapshot!(
p(10.hours().minutes(10).seconds(10)),
@"10:10:10",
);
insta::assert_snapshot!(
p(100.hours().minutes(100).seconds(100)),
@"100:100:100",
);
insta::assert_snapshot!(
p(1.day().hours(1).minutes(1).seconds(1)),
@"1d 01:01:01",
);
insta::assert_snapshot!(
p(1.day()),
@"1d 00:00:00",
);
insta::assert_snapshot!(
p(1.day().seconds(2)),
@"1d 00:00:02",
);
}
#[test]
fn print_span_hms_fmt() {
let printer = || {
SpanPrinter::new()
.hours_minutes_seconds(true)
.comma_after_designator(true)
.spacing(Spacing::BetweenUnitsAndDesignators)
};
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(
p(1.day().hours(1).minutes(1).seconds(1)),
@"1 d, 01:01:01",
);
insta::assert_snapshot!(
p(1.year().months(1).weeks(1).days(1).hours(1).minutes(1).seconds(1)),
@"1 y, 1 mo, 1 w, 1 d, 01:01:01",
);
insta::assert_snapshot!(
p(1.day().hours(1).minutes(1).seconds(1).nanoseconds(1)),
@"1 d, 01:01:01.000000001",
);
}
#[test]
fn print_span_hms_sign() {
let printer = |direction| {
SpanPrinter::new().hours_minutes_seconds(true).direction(direction)
};
let p = |direction, span| printer(direction).span_to_string(&span);
insta::assert_snapshot!(
p(Direction::Auto, 1.hour()),
@"01:00:00",
);
insta::assert_snapshot!(
p(Direction::Sign, 1.hour()),
@"01:00:00",
);
insta::assert_snapshot!(
p(Direction::ForceSign, 1.hour()),
@"+01:00:00",
);
insta::assert_snapshot!(
p(Direction::Suffix, 1.hour()),
@"01:00:00",
);
insta::assert_snapshot!(
p(Direction::Auto, -1.hour()),
@"-01:00:00",
);
insta::assert_snapshot!(
p(Direction::Sign, -1.hour()),
@"-01:00:00",
);
insta::assert_snapshot!(
p(Direction::ForceSign, -1.hour()),
@"-01:00:00",
);
insta::assert_snapshot!(
p(Direction::Suffix, -1.hour()),
@"01:00:00 ago",
);
insta::assert_snapshot!(
p(Direction::Auto, 1.day().hours(1)),
@"1d 01:00:00",
);
insta::assert_snapshot!(
p(Direction::Sign, 1.day().hours(1)),
@"1d 01:00:00",
);
insta::assert_snapshot!(
p(Direction::ForceSign, 1.day().hours(1)),
@"+1d 01:00:00",
);
insta::assert_snapshot!(
p(Direction::Suffix, 1.day().hours(1)),
@"1d 01:00:00",
);
insta::assert_snapshot!(
p(Direction::Auto, -1.day().hours(1)),
@"1d 01:00:00 ago",
);
insta::assert_snapshot!(
p(Direction::Sign, -1.day().hours(1)),
@"-1d 01:00:00",
);
insta::assert_snapshot!(
p(Direction::ForceSign, -1.day().hours(1)),
@"-1d 01:00:00",
);
insta::assert_snapshot!(
p(Direction::Suffix, -1.day().hours(1)),
@"1d 01:00:00 ago",
);
}
#[test]
fn print_span_hms_fraction_auto() {
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
let p = |span| printer().span_to_string(&span);
insta::assert_snapshot!(p(1.nanosecond()), @"00:00:00.000000001");
insta::assert_snapshot!(p(-1.nanosecond()), @"-00:00:00.000000001");
insta::assert_snapshot!(
printer().direction(Direction::ForceSign).span_to_string(&1.nanosecond()),
@"+00:00:00.000000001",
);
insta::assert_snapshot!(
p(1.second().nanoseconds(123)),
@"00:00:01.000000123",
);
insta::assert_snapshot!(
p(1.second().milliseconds(123)),
@"00:00:01.123",
);
insta::assert_snapshot!(
p(1.second().milliseconds(1_123)),
@"00:00:02.123",
);
insta::assert_snapshot!(
p(1.second().milliseconds(61_123)),
@"00:00:62.123",
);
}
#[test]
fn print_span_hms_fraction_fixed_precision() {
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
let p = |precision, span| {
printer().precision(Some(precision)).span_to_string(&span)
};
insta::assert_snapshot!(p(3, 1.second()), @"00:00:01.000");
insta::assert_snapshot!(
p(3, 1.second().milliseconds(1)),
@"00:00:01.001",
);
insta::assert_snapshot!(
p(3, 1.second().milliseconds(123)),
@"00:00:01.123",
);
insta::assert_snapshot!(
p(3, 1.second().milliseconds(100)),
@"00:00:01.100",
);
insta::assert_snapshot!(p(0, 1.second()), @"00:00:01");
insta::assert_snapshot!(p(0, 1.second().milliseconds(1)), @"00:00:01");
insta::assert_snapshot!(
p(1, 1.second().milliseconds(999)),
@"00:00:01.9",
);
}
#[test]
fn print_duration_hms() {
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
let p = |secs| {
printer().duration_to_string(&SignedDuration::from_secs(secs))
};
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_duration_hms_sign() {
let printer = |direction| {
SpanPrinter::new().hours_minutes_seconds(true).direction(direction)
};
let p = |direction, secs| {
printer(direction)
.duration_to_string(&SignedDuration::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");
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 ago");
}
#[test]
fn print_duration_hms_fraction_auto() {
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
let p = |secs, nanos| {
printer().duration_to_string(&SignedDuration::new(secs, nanos))
};
insta::assert_snapshot!(p(0, 1), @"00:00:00.000000001");
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_duration_hms_fraction_fixed_precision() {
let printer = || SpanPrinter::new().hours_minutes_seconds(true);
let p = |precision, secs, nanos| {
printer()
.precision(Some(precision))
.duration_to_string(&SignedDuration::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",
);
}
}