use core::fmt; use std::{ops::ControlFlow, time::Duration}; pub(crate) fn format_duration_into(dur: Duration, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn item(unit: &'static str, value: u64) -> ControlFlow<(&'static str, u64)> { if value > 0 { ControlFlow::Break((unit, value)) } else { ControlFlow::Continue(()) } } // impl taken and modified from // https://github.com/tailhook/humantime/blob/master/src/duration.rs#L295-L331 // Copyright (c) 2016 The humantime Developers fn fmt(f: Duration) -> ControlFlow<(&'static str, u64), ()> { let secs = f.as_secs(); let nanos = f.subsec_nanos(); let years = secs / 31_557_600; // 365.25d let year_days = secs % 31_557_600; let months = year_days / 2_630_016; // 30.44d let month_days = year_days % 2_630_016; let days = month_days / 86400; let day_secs = month_days % 86400; let hours = day_secs / 3600; let minutes = day_secs % 3600 / 60; let seconds = day_secs % 60; let millis = nanos / 1_000_000; let micros = nanos / 1_000; // a difference from our impl than the original is that // we only care about the most-significant segment of the duration. // If the item call returns `Break`, then the `?` will early-return. // This allows for a very consise impl item("y", years)?; item("mo", months)?; item("d", days)?; item("h", hours)?; item("m", minutes)?; item("s", seconds)?; item("ms", u64::from(millis))?; item("us", u64::from(micros))?; item("ns", u64::from(nanos))?; ControlFlow::Continue(()) } match fmt(dur) { ControlFlow::Break((unit, value)) => write!(f, "{value}{unit}"), ControlFlow::Continue(()) => write!(f, "0s"), } } pub(crate) fn format_duration(f: Duration) -> String { struct F(Duration); impl fmt::Display for F { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { format_duration_into(self.0, f) } } F(f).to_string() }