use std::time::Duration;
#[must_use]
pub fn format_duration(duration: Duration) -> String {
let total_secs = duration.as_secs();
let sub_secs_millis = duration.subsec_millis();
if total_secs == 0 {
let min_millis = u32::from(!duration.is_zero());
let millis = sub_secs_millis.max(min_millis);
return format!("{millis}ms");
}
if total_secs < 60 {
return format!("{total_secs}s {sub_secs_millis}ms");
}
let total_minutes = total_secs / 60;
let seconds_part = total_secs % 60;
if total_minutes < 60 {
return format!("{total_minutes}m {seconds_part}s");
}
let total_hours = total_minutes / 60;
let minutes_part = total_minutes % 60;
format!("{total_hours}h {minutes_part}m")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sub_millisecond_renders_as_one_ms() {
assert_eq!(format_duration(Duration::from_micros(500)), "1ms");
}
#[test]
fn zero_renders_as_zero_ms() {
assert_eq!(format_duration(Duration::ZERO), "0ms");
}
#[test]
fn millisecond_grain_under_one_second() {
assert_eq!(format_duration(Duration::from_millis(176)), "176ms");
assert_eq!(format_duration(Duration::from_millis(999)), "999ms");
}
#[test]
fn second_plus_millisecond_under_one_minute() {
assert_eq!(format_duration(Duration::from_millis(7_856)), "7s 856ms");
assert_eq!(format_duration(Duration::from_secs(1)), "1s 0ms");
assert_eq!(format_duration(Duration::from_millis(59_999)), "59s 999ms");
}
#[test]
fn minute_plus_second_under_one_hour() {
assert_eq!(format_duration(Duration::from_mins(1)), "1m 0s");
assert_eq!(format_duration(Duration::from_secs(83)), "1m 23s");
assert_eq!(format_duration(Duration::from_secs(3_599)), "59m 59s");
}
#[test]
fn hour_plus_minute() {
assert_eq!(format_duration(Duration::from_hours(1)), "1h 0m");
assert_eq!(format_duration(Duration::from_mins(83)), "1h 23m");
}
}