loaders 0.0.0

A fully-featured, customisable progress bar and loading indicator library for Rust CLI and terminal applications
Documentation
//! Duration formatting used by elapsed and ETA template variables.

use std::time::Duration;

/// Formats a duration using compact human-readable units.
///
/// # Examples
///
/// ```rust
/// use std::time::Duration;
/// assert_eq!(loaders::utils::duration::format_duration(Duration::from_secs(74)), "1m 14s");
/// ```
pub fn format_duration(d: Duration) -> String {
    let secs = d.as_secs();
    let hours = secs / 3600;
    let minutes = (secs % 3600) / 60;
    let seconds = secs % 60;

    if hours > 0 {
        format!("{hours}h {minutes:02}m {seconds:02}s")
    } else if minutes > 0 {
        format!("{minutes}m {seconds:02}s")
    } else {
        format!("{seconds}s")
    }
}

/// Formats a duration as `HH:MM:SS`.
///
/// # Examples
///
/// ```rust
/// use std::time::Duration;
/// assert_eq!(loaders::utils::duration::format_duration_precise(Duration::from_secs(3661)), "01:01:01");
/// ```
pub fn format_duration_precise(d: Duration) -> String {
    let secs = d.as_secs();
    format!(
        "{:02}:{:02}:{:02}",
        secs / 3600,
        (secs % 3600) / 60,
        secs % 60
    )
}

/// Formats a duration as `HH:MM:SS.mmm`.
///
/// # Examples
///
/// ```rust
/// use std::time::Duration;
/// assert_eq!(loaders::utils::duration::format_duration_millis(Duration::from_millis(1)), "00:00:00.001");
/// ```
pub fn format_duration_millis(d: Duration) -> String {
    format!("{}.{:03}", format_duration_precise(d), d.subsec_millis())
}

/// Formats an estimated remaining duration with a leading approximation marker.
///
/// # Examples
///
/// ```rust
/// use std::time::Duration;
/// assert_eq!(loaders::utils::duration::format_eta(Duration::from_secs(2)), "~2s");
/// ```
pub fn format_eta(d: Duration) -> String {
    format!("~{}", format_duration(d))
}

/// Formats elapsed time without an approximation marker.
///
/// # Examples
///
/// ```rust
/// use std::time::Duration;
/// assert_eq!(loaders::utils::duration::format_elapsed(Duration::from_secs(2)), "2s");
/// ```
pub fn format_elapsed(d: Duration) -> String {
    format_duration(d)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_format_zero_duration() {
        assert_eq!(format_duration(Duration::ZERO), "0s");
    }

    #[test]
    fn test_format_seconds() {
        assert_eq!(format_duration(Duration::from_secs(42)), "42s");
    }

    #[test]
    fn test_format_minutes_seconds() {
        assert_eq!(format_duration(Duration::from_secs(194)), "3m 14s");
    }

    #[test]
    fn test_format_hours_minutes_seconds() {
        assert_eq!(format_duration(Duration::from_secs(4984)), "1h 23m 04s");
    }

    #[test]
    fn test_format_precise_padding() {
        assert_eq!(
            format_duration_precise(Duration::from_secs(4984)),
            "01:23:04"
        );
    }

    #[test]
    fn test_format_millis() {
        assert_eq!(
            format_duration_millis(Duration::from_millis(4_984_123)),
            "01:23:04.123"
        );
    }

    #[test]
    fn test_format_eta_adds_tilde() {
        assert_eq!(format_eta(Duration::from_secs(42)), "~42s");
    }

    #[test]
    fn test_format_elapsed_no_tilde() {
        assert_eq!(format_elapsed(Duration::from_secs(42)), "42s");
    }
}