use crate::{
fmt::{
buffer::{ArrayBuffer, BorrowedBuffer},
Write,
},
Error, SignedDuration, Span, Unit,
};
const SECS_PER_HOUR: u64 = MINS_PER_HOUR * SECS_PER_MIN;
const SECS_PER_MIN: u64 = 60;
const MINS_PER_HOUR: u64 = 60;
const NANOS_PER_HOUR: u128 =
(SECS_PER_MIN * MINS_PER_HOUR * NANOS_PER_SEC) as u128;
const NANOS_PER_MIN: u128 = (SECS_PER_MIN * NANOS_PER_SEC) as u128;
const NANOS_PER_SEC: u64 = 1_000_000_000;
const NANOS_PER_MILLI: u32 = 1_000_000;
const NANOS_PER_MICRO: u32 = 1_000;
const MAX_SPAN_LEN: usize = 306;
const MAX_SIGNED_DURATION_LEN: usize = 194;
const MAX_UNSIGNED_DURATION_LEN: usize = 190;
#[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) -> Option<u8> {
match self {
Spacing::None => None,
Spacing::BetweenUnits => Some(b' '),
Spacing::BetweenUnitsAndDesignators => Some(b' '),
}
}
fn between_units_and_designators(self) -> Option<u8> {
match self {
Spacing::None => None,
Spacing::BetweenUnits => None,
Spacing::BetweenUnitsAndDesignators => Some(b' '),
}
}
}
#[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(b'-'))
} else {
None
}
}
Spacing::BetweenUnits
| Spacing::BetweenUnitsAndDesignators => {
if signum < 0 {
if printer.hms && !has_calendar {
Some(DirectionSign::Prefix(b'-'))
} else {
Some(DirectionSign::Suffix)
}
} else {
None
}
}
},
Direction::Sign => {
if signum < 0 {
Some(DirectionSign::Prefix(b'-'))
} else {
None
}
}
Direction::ForceSign => {
Some(DirectionSign::Prefix(if signum < 0 {
b'-'
} else {
b'+'
}))
}
Direction::Suffix => {
if signum < 0 {
Some(DirectionSign::Suffix)
} else {
None
}
}
}
}
}
#[derive(Clone, Copy, Debug)]
enum DirectionSign {
Prefix(u8),
Suffix,
}
#[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 {
designators: &'static Designators,
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 {
designators: Designators::new(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 { designators: Designators::new(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
}
#[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);
self.print_unsigned_duration(duration, &mut buf).unwrap();
buf
}
pub fn print_span<W: Write>(
&self,
span: &Span,
mut wtr: W,
) -> Result<(), Error> {
let mut buf = ArrayBuffer::<MAX_SPAN_LEN>::default();
let mut bbuf = buf.as_borrowed();
if self.hms {
self.print_span_hms(span, &mut bbuf);
} else {
self.print_span_designators(span, &mut bbuf);
}
wtr.write_str(bbuf.filled())
}
pub fn print_duration<W: Write>(
&self,
duration: &SignedDuration,
mut wtr: W,
) -> Result<(), Error> {
let mut buf = ArrayBuffer::<MAX_SIGNED_DURATION_LEN>::default();
let mut bbuf = buf.as_borrowed();
if self.hms {
self.print_signed_duration_hms(duration, &mut bbuf);
} else {
self.print_signed_duration_designators(duration, &mut bbuf);
}
wtr.write_str(bbuf.filled())
}
pub fn print_unsigned_duration<W: Write>(
&self,
duration: &core::time::Duration,
mut wtr: W,
) -> Result<(), Error> {
let mut buf = ArrayBuffer::<MAX_UNSIGNED_DURATION_LEN>::default();
let mut bbuf = buf.as_borrowed();
if self.hms {
self.print_unsigned_duration_hms(duration, &mut bbuf);
} else {
self.print_unsigned_duration_designators(duration, &mut bbuf);
}
wtr.write_str(bbuf.filled())
}
fn print_span_designators(
&self,
span: &Span,
bbuf: &mut BorrowedBuffer<'_>,
) {
let mut wtr = DesignatorWriter::new(self, bbuf, 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();
}
fn print_span_designators_non_fraction<'p, 'w, 'd>(
&self,
span: &Span,
wtr: &mut DesignatorWriter<'p, 'w, 'd>,
) {
let units = span.units();
if units.contains(Unit::Year) {
wtr.write(Unit::Year, span.get_years_unsigned().into());
}
if units.contains(Unit::Month) {
wtr.write(Unit::Month, span.get_months_unsigned().into());
}
if units.contains(Unit::Week) {
wtr.write(Unit::Week, span.get_weeks_unsigned().into());
}
if units.contains(Unit::Day) {
wtr.write(Unit::Day, span.get_days_unsigned().into());
}
if units.contains(Unit::Hour) {
wtr.write(Unit::Hour, span.get_hours_unsigned().into());
}
if units.contains(Unit::Minute) {
wtr.write(Unit::Minute, span.get_minutes_unsigned());
}
if units.contains(Unit::Second) {
wtr.write(Unit::Second, span.get_seconds_unsigned());
}
if units.contains(Unit::Millisecond) {
wtr.write(Unit::Millisecond, span.get_milliseconds_unsigned());
}
if units.contains(Unit::Microsecond) {
wtr.write(Unit::Microsecond, span.get_microseconds_unsigned());
}
if units.contains(Unit::Nanosecond) {
wtr.write(Unit::Nanosecond, span.get_nanoseconds_unsigned());
}
}
fn print_span_calendar_designators_non_fraction<'p, 'w, 'd>(
&self,
span: &Span,
wtr: &mut DesignatorWriter<'p, 'w, 'd>,
) {
let units = span.units();
if units.contains(Unit::Year) {
wtr.write(Unit::Year, span.get_years_unsigned().into());
}
if units.contains(Unit::Month) {
wtr.write(Unit::Month, span.get_months_unsigned().into());
}
if units.contains(Unit::Week) {
wtr.write(Unit::Week, span.get_weeks_unsigned().into());
}
if units.contains(Unit::Day) {
wtr.write(Unit::Day, span.get_days_unsigned().into());
}
}
#[inline(never)]
fn print_span_designators_fractional<'p, 'w, 'd>(
&self,
span: &Span,
unit: FractionalUnit,
wtr: &mut DesignatorWriter<'p, 'w, 'd>,
) {
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_invariant_duration().unsigned_abs(),
);
}
fn print_span_hms(&self, span: &Span, bbuf: &mut BorrowedBuffer<'_>) {
let has_cal = !span.units().only_calendar().is_empty();
let mut wtr =
DesignatorWriter::new(self, bbuf, has_cal, span.signum());
let span = span.abs();
wtr.maybe_write_prefix_sign();
if has_cal {
self.print_span_calendar_designators_non_fraction(&span, &mut wtr);
wtr.finish_preceding();
if matches!(self.spacing, Spacing::None) {
wtr.bbuf.write_ascii_char(b' ');
}
}
let padding = self.padding.unwrap_or(2);
wtr.bbuf.write_int_pad(span.get_hours_unsigned(), b'0', padding);
wtr.bbuf.write_ascii_char(b':');
wtr.bbuf.write_int_pad(span.get_minutes_unsigned(), b'0', padding);
wtr.bbuf.write_ascii_char(b':');
let fp = FractionalPrinter::from_span_seconds(
&span.only_lower(Unit::Minute),
padding,
self.precision,
);
fp.print(wtr.bbuf);
wtr.maybe_write_suffix_sign();
}
fn print_signed_duration_designators(
&self,
dur: &SignedDuration,
bbuf: &mut BorrowedBuffer<'_>,
) {
let mut wtr = DesignatorWriter::new(self, bbuf, false, dur.signum());
wtr.maybe_write_prefix_sign();
self.print_duration_designators(&dur.unsigned_abs(), &mut wtr);
wtr.maybe_write_zero();
wtr.maybe_write_suffix_sign();
}
fn print_unsigned_duration_designators(
&self,
dur: &core::time::Duration,
bbuf: &mut BorrowedBuffer<'_>,
) {
let mut wtr = DesignatorWriter::new(self, bbuf, false, 1);
wtr.maybe_write_prefix_sign();
self.print_duration_designators(dur, &mut wtr);
wtr.maybe_write_zero();
}
fn print_duration_designators(
&self,
dur: &core::time::Duration,
wtr: &mut DesignatorWriter<'_, '_, '_>,
) {
match self.fractional {
None => {
let mut secs = dur.as_secs();
wtr.write(Unit::Hour, secs / SECS_PER_HOUR);
secs %= MINS_PER_HOUR * SECS_PER_MIN;
wtr.write(Unit::Minute, secs / SECS_PER_MIN);
wtr.write(Unit::Second, secs % SECS_PER_MIN);
let mut nanos = dur.subsec_nanos();
wtr.write(Unit::Millisecond, (nanos / NANOS_PER_MILLI).into());
nanos %= NANOS_PER_MILLI;
wtr.write(Unit::Microsecond, (nanos / NANOS_PER_MICRO).into());
wtr.write(Unit::Nanosecond, (nanos % NANOS_PER_MICRO).into());
}
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);
secs %= MINS_PER_HOUR * SECS_PER_MIN;
let leftovers =
core::time::Duration::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);
secs %= MINS_PER_HOUR * SECS_PER_MIN;
wtr.write(Unit::Minute, secs / SECS_PER_MIN);
secs %= SECS_PER_MIN;
let leftovers =
core::time::Duration::new(secs, dur.subsec_nanos());
wtr.write_fractional_duration(
FractionalUnit::Second,
&leftovers,
);
}
Some(FractionalUnit::Millisecond) => {
let mut secs = dur.as_secs();
wtr.write(Unit::Hour, secs / SECS_PER_HOUR);
secs %= MINS_PER_HOUR * SECS_PER_MIN;
wtr.write(Unit::Minute, secs / SECS_PER_MIN);
wtr.write(Unit::Second, secs % SECS_PER_MIN);
let leftovers =
core::time::Duration::new(0, dur.subsec_nanos());
wtr.write_fractional_duration(
FractionalUnit::Millisecond,
&leftovers,
);
}
Some(FractionalUnit::Microsecond) => {
let mut secs = dur.as_secs();
wtr.write(Unit::Hour, secs / SECS_PER_HOUR);
secs %= MINS_PER_HOUR * SECS_PER_MIN;
wtr.write(Unit::Minute, secs / SECS_PER_MIN);
wtr.write(Unit::Second, secs % SECS_PER_MIN);
let mut nanos = dur.subsec_nanos();
wtr.write(Unit::Millisecond, (nanos / NANOS_PER_MILLI).into());
nanos %= NANOS_PER_MILLI;
let leftovers = core::time::Duration::new(0, nanos);
wtr.write_fractional_duration(
FractionalUnit::Microsecond,
&leftovers,
);
}
}
}
fn print_signed_duration_hms(
&self,
dur: &SignedDuration,
bbuf: &mut BorrowedBuffer<'_>,
) {
if dur.is_negative() {
if !matches!(self.direction, Direction::Suffix) {
bbuf.write_ascii_char(b'-');
}
} else if let Direction::ForceSign = self.direction {
bbuf.write_ascii_char(b'+');
}
self.print_duration_hms(&dur.unsigned_abs(), bbuf);
if dur.is_negative() {
if matches!(self.direction, Direction::Suffix) {
bbuf.write_str(" ago");
}
}
}
fn print_unsigned_duration_hms(
&self,
dur: &core::time::Duration,
bbuf: &mut BorrowedBuffer<'_>,
) {
if let Direction::ForceSign = self.direction {
bbuf.write_ascii_char(b'+');
}
self.print_duration_hms(dur, bbuf);
}
fn print_duration_hms(
&self,
udur: &core::time::Duration,
bbuf: &mut BorrowedBuffer<'_>,
) {
let padding = self.padding.unwrap_or(2);
let mut secs = udur.as_secs();
let hours = secs / (MINS_PER_HOUR * SECS_PER_MIN);
secs %= MINS_PER_HOUR * SECS_PER_MIN;
let minutes = secs / SECS_PER_MIN;
secs = secs % SECS_PER_MIN;
bbuf.write_int_pad(hours, b'0', padding);
bbuf.write_ascii_char(b':');
bbuf.write_int_pad(minutes, b'0', padding);
bbuf.write_ascii_char(b':');
let fp = FractionalPrinter::from_duration_seconds(
&core::time::Duration::new(secs, udur.subsec_nanos()),
padding,
self.precision,
);
fp.print(bbuf);
}
}
impl Default for SpanPrinter {
fn default() -> SpanPrinter {
SpanPrinter::new()
}
}
#[derive(Clone, Debug)]
struct Designators {
singular: [&'static str; 10],
plural: [&'static str; 10],
}
impl Designators {
const VERBOSE_SINGULAR: [&'static str; 10] = [
"nanosecond",
"microsecond",
"millisecond",
"second",
"minute",
"hour",
"day",
"week",
"month",
"year",
];
const VERBOSE_PLURAL: [&'static str; 10] = [
"nanoseconds",
"microseconds",
"milliseconds",
"seconds",
"minutes",
"hours",
"days",
"weeks",
"months",
"years",
];
const SHORT_SINGULAR: [&'static str; 10] =
["nsec", "µsec", "msec", "sec", "min", "hr", "day", "wk", "mo", "yr"];
const SHORT_PLURAL: [&'static str; 10] = [
"nsecs", "µsecs", "msecs", "secs", "mins", "hrs", "days", "wks",
"mos", "yrs",
];
const COMPACT: [&'static str; 10] =
["ns", "µs", "ms", "s", "m", "h", "d", "w", "mo", "y"];
const HUMAN_TIME_SINGULAR: [&'static str; 10] =
["ns", "us", "ms", "s", "m", "h", "d", "w", "month", "y"];
const HUMAN_TIME_PLURAL: [&'static str; 10] =
["ns", "us", "ms", "s", "m", "h", "d", "w", "months", "y"];
const fn new(config: Designator) -> &'static 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, 'd> {
printer: &'p SpanPrinter,
bbuf: &'w mut BorrowedBuffer<'d>,
sign: Option<DirectionSign>,
padding: u8,
precision: Option<u8>,
written_non_zero_unit: bool,
}
impl<'p, 'w, 'd> DesignatorWriter<'p, 'w, 'd> {
fn new(
printer: &'p SpanPrinter,
bbuf: &'w mut BorrowedBuffer<'d>,
has_calendar: bool,
signum: i8,
) -> DesignatorWriter<'p, 'w, 'd> {
let sign = printer.direction.sign(printer, has_calendar, signum);
DesignatorWriter {
printer,
bbuf,
sign,
padding: printer.padding.unwrap_or(0),
precision: printer.precision,
written_non_zero_unit: false,
}
}
fn maybe_write_prefix_sign(&mut self) {
if let Some(DirectionSign::Prefix(sign)) = self.sign {
self.bbuf.write_ascii_char(sign);
}
}
fn maybe_write_suffix_sign(&mut self) {
if let Some(DirectionSign::Suffix) = self.sign {
self.bbuf.write_str(" ago");
}
}
fn maybe_write_zero(&mut self) {
#[cold]
#[inline(never)]
fn imp(wtr: &mut DesignatorWriter<'_, '_, '_>) {
wtr.bbuf.write_int_pad(0u64, b'0', wtr.padding);
if let Some(byte) =
wtr.printer.spacing.between_units_and_designators()
{
wtr.bbuf.write_ascii_char(byte);
}
let unit = wtr
.printer
.fractional
.map(Unit::from)
.unwrap_or(wtr.printer.zero_unit);
wtr.bbuf.write_str(wtr.printer.designators.designator(unit, true));
}
if !self.written_non_zero_unit {
imp(self);
}
}
#[inline(never)]
fn write(&mut self, unit: Unit, value: u64) {
if value == 0 {
return;
}
self.finish_preceding();
self.written_non_zero_unit = true;
self.bbuf.write_int_pad0(value, self.padding);
if let Some(byte) =
self.printer.spacing.between_units_and_designators()
{
self.bbuf.write_ascii_char(byte);
}
self.bbuf
.write_str(self.printer.designators.designator(unit, value != 1));
}
fn write_fractional_duration(
&mut self,
unit: FractionalUnit,
duration: &core::time::Duration,
) {
let fp = FractionalPrinter::from_duration(
duration,
unit,
self.padding,
self.precision,
);
if !fp.must_write_digits() {
return;
}
self.finish_preceding();
self.written_non_zero_unit = true;
fp.print(&mut *self.bbuf);
if let Some(byte) =
self.printer.spacing.between_units_and_designators()
{
self.bbuf.write_ascii_char(byte);
}
self.bbuf.write_str(
self.printer.designators.designator(unit, fp.is_plural()),
);
}
fn finish_preceding(&mut self) {
if self.written_non_zero_unit {
if self.printer.comma_after_designator {
self.bbuf.write_ascii_char(b',');
}
if let Some(byte) = self.printer.spacing.between_units() {
self.bbuf.write_ascii_char(byte);
}
}
}
}
struct FractionalPrinter {
integer: u64,
fraction: u32,
padding: u8,
precision: Option<u8>,
}
impl FractionalPrinter {
fn from_span_seconds(
span: &Span,
padding: u8,
precision: Option<u8>,
) -> FractionalPrinter {
FractionalPrinter::from_duration_seconds(
&span.to_invariant_duration().unsigned_abs(),
padding,
precision,
)
}
fn from_duration_seconds(
dur: &core::time::Duration,
padding: u8,
precision: Option<u8>,
) -> FractionalPrinter {
let integer = dur.as_secs();
let fraction = u32::from(dur.subsec_nanos());
FractionalPrinter { integer, fraction, padding, precision }
}
fn from_duration(
dur: &core::time::Duration,
unit: FractionalUnit,
padding: u8,
precision: Option<u8>,
) -> FractionalPrinter {
match unit {
FractionalUnit::Hour => {
let integer = dur.as_secs() / SECS_PER_HOUR;
let mut fraction = dur.as_nanos() % NANOS_PER_HOUR;
fraction /= u128::from(SECS_PER_HOUR);
let fraction = u32::try_from(fraction).unwrap();
FractionalPrinter { integer, fraction, padding, precision }
}
FractionalUnit::Minute => {
let integer = dur.as_secs() / SECS_PER_MIN;
let mut fraction = dur.as_nanos() % NANOS_PER_MIN;
fraction /= u128::from(SECS_PER_MIN);
let fraction = u32::try_from(fraction).unwrap();
FractionalPrinter { integer, fraction, padding, precision }
}
FractionalUnit::Second => {
let integer = dur.as_secs();
let fraction = u32::from(dur.subsec_nanos());
FractionalPrinter { integer, fraction, padding, precision }
}
FractionalUnit::Millisecond => {
let integer = u64::try_from(dur.as_millis()).unwrap();
let fraction =
u32::from((dur.subsec_nanos() % NANOS_PER_MILLI) * 1_000);
FractionalPrinter { integer, fraction, padding, precision }
}
FractionalUnit::Microsecond => {
let integer = u64::try_from(dur.as_micros()).unwrap();
let fraction = u32::from(
(dur.subsec_nanos() % NANOS_PER_MICRO) * 1_000_000,
);
FractionalPrinter { integer, fraction, padding, precision }
}
}
}
fn is_zero(&self) -> bool {
self.integer == 0 && self.fraction == 0
}
fn is_plural(&self) -> bool {
self.integer != 1
|| (self.fraction != 0 && !self.has_zero_fixed_precision())
}
fn must_write_digits(&self) -> bool {
!self.is_zero() || self.has_non_zero_fixed_precision()
}
fn will_write_digits(&self) -> bool {
self.precision.map_or_else(|| self.fraction != 0, |p| p > 0)
}
fn has_non_zero_fixed_precision(&self) -> bool {
self.precision.map_or(false, |p| p > 0)
}
fn has_zero_fixed_precision(&self) -> bool {
self.precision.map_or(false, |p| p == 0)
}
fn print(&self, bbuf: &mut BorrowedBuffer<'_>) {
bbuf.write_int_pad(self.integer, b'0', self.padding);
if self.will_write_digits() {
bbuf.write_ascii_char(b'.');
bbuf.write_fraction(self.precision, self.fraction);
}
}
}
#[cfg(feature = "alloc")]
#[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_signed_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_signed_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_signed_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_signed_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_signed_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_signed_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_signed_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_signed_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_signed_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_signed_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_signed_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_signed_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_signed_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_signed_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_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");
insta::assert_snapshot!(p(1, 1), @"0.000277777h");
insta::assert_snapshot!(p(0, 0), @"0h");
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");
insta::assert_snapshot!(p(1, 1), @"0.016666666m");
insta::assert_snapshot!(p(0, 0), @"0m");
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);
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_signed_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_signed_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_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))
};
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_signed_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",
);
}
#[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),
)
};
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",
);
}
#[test]
fn maximums() {
let p = SpanPrinter::new()
.padding(u8::MAX)
.designator(Designator::Verbose)
.spacing(Spacing::BetweenUnitsAndDesignators)
.comma_after_designator(true);
let span = -19_998
.year()
.months(239_976)
.weeks(1_043_497)
.days(7_304_484)
.hours(175_307_616)
.minutes(10_518_456_960i64)
.seconds(631_107_417_600i64)
.milliseconds(631_107_417_600_000i64)
.microseconds(631_107_416_600_000_000i64)
.nanoseconds(9_223_372_036_854_775_807i64);
insta::assert_snapshot!(
p.span_to_string(&span),
@"00000000000000019998 years, 00000000000000239976 months, 00000000000001043497 weeks, 00000000000007304484 days, 00000000000175307616 hours, 00000000010518456960 minutes, 00000000631107417600 seconds, 00000631107417600000 milliseconds, 00631107416600000000 microseconds, 09223372036854775807 nanoseconds ago",
);
let sdur = SignedDuration::MAX;
insta::assert_snapshot!(
p.duration_to_string(&sdur),
@"00002562047788015215 hours, 00000000000000000030 minutes, 00000000000000000007 seconds, 00000000000000000999 milliseconds, 00000000000000000999 microseconds, 00000000000000000999 nanoseconds",
);
let udur =
core::time::Duration::MAX - core::time::Duration::from_secs(16);
insta::assert_snapshot!(
p.unsigned_duration_to_string(&udur),
@"00005124095576030430 hours, 00000000000000000059 minutes, 00000000000000000059 seconds, 00000000000000000999 milliseconds, 00000000000000000999 microseconds, 00000000000000000999 nanoseconds",
);
}
}