units-formatter 0.1.2

A simple library to format units
Documentation
use std::time::Duration;

// 单位换算因子(整数)
const NS_PER_US: u128 = 1_000;
const NS_PER_MS: u128 = 1_000_000;
const NS_PER_S: u128 = 1_000_000_000;
const NS_PER_MIN: u128 = 60 * NS_PER_S;
const NS_PER_H: u128 = 60 * NS_PER_MIN;

/// 将 `Duration` 格式化为带单位的字符串,自动选择最合适的单位。
///
/// # 参数
/// - `duration`: 要格式化的时间长度。
/// - `round`: 可选的小数精度(默认保留 2 位,最大 9 位)。
///
/// # 返回
/// 返回一个字符串,例如 `"2.00s"`、`"123.45ms"`、`"1.50min"`、`"0.50h"` 等。
///
/// # 示例
/// ```
/// use std::time::Duration;
/// use units_formatter::time::format_duration;
///
/// let d = Duration::from_secs(2);
/// assert_eq!(format_duration(d, Some(2)), "2.00s");
///
/// let d = Duration::from_nanos(1_234_567_890);
/// assert_eq!(format_duration(d, Some(3)), "1.234s");
/// ```
#[inline]
pub fn format_duration(duration: Duration, round: Option<u8>) -> String {
    let precision = round.unwrap_or(2).min(9) as usize; // 纳秒最多 9 位小数
    let total_ns = duration.as_nanos();

    // 根据纳秒范围确定单位
    let (unit_value, unit_name, divisor) = if total_ns < NS_PER_US {
        (total_ns, "ns", 1)
    } else if total_ns < NS_PER_MS {
        (total_ns, "μs", NS_PER_US)
    } else if total_ns < NS_PER_S {
        (total_ns, "ms", NS_PER_MS)
    } else if total_ns < NS_PER_MIN {
        (total_ns, "s", NS_PER_S)
    } else if total_ns < NS_PER_H {
        (total_ns, "min", NS_PER_MIN)
    } else {
        (total_ns, "h", NS_PER_H)
    };

    // 整数部分
    let integer_part = unit_value / divisor;
    let remainder = unit_value % divisor;

    if remainder == 0 && precision == 0 {
        // 无小数部分且不要求小数位
        format!("{}{}", integer_part, unit_name)
    } else {
        // 计算小数部分:将余数放大到所需精度,再除以除数
        // 注意:使用截断(floor),如需四舍五入可改为 (remainder * scale + divisor/2) / divisor
        let scale = 10u128.pow(precision as u32);
        let fractional = (remainder * scale) / divisor;

        // 格式化:整数部分 + 小数点 + 小数部分(补零到指定位数)
        format!(
            "{}.{:0width$}{}",
            integer_part,
            fractional,
            unit_name,
            width = precision
        )
    }
}

/// 将 `Duration` 格式化为更人类友好的字符串,按小时、分钟、秒显示。
///
/// # 参数
/// - `duration`: 要格式化的时间长度。
///
/// # 返回
/// 返回一个字符串,例如 `"01h 30m 45s"`、`"05m 12s"`、`"00s 123ms"` 等。
pub fn format_better_duration(duration: Duration) -> String {
    let sec = duration.as_secs();
    let min = sec / 60;
    let h = min / 60;

    if h > 0 {
        return format!("{:02}h {:02}m {:02}s", h, min, sec);
    } else if min > 0 {
        return format!("{:02}m {:02}s", min, sec);
    }
    let ms = duration.subsec_millis();
    format!("{:02}s {:03}ms", sec, ms)
}