#serialization #format-duration #byte

no-std human-units

Units serialization and formatting library designed for configuration files and command line arguments

14 unstable releases (4 breaking)

0.5.3 Aug 3, 2025
0.5.2 Jul 25, 2025
0.4.0 Jul 5, 2025
0.3.0 Mar 16, 2025
0.1.6 Sep 16, 2024

#218 in Encoding

Download history 1106/week @ 2025-10-26 547/week @ 2025-11-02 584/week @ 2025-11-09 565/week @ 2025-11-16 471/week @ 2025-11-23 794/week @ 2025-11-30 804/week @ 2025-12-07 692/week @ 2025-12-14 565/week @ 2025-12-21 812/week @ 2025-12-28 666/week @ 2026-01-04 836/week @ 2026-01-11 2092/week @ 2026-01-18 715/week @ 2026-01-25 1480/week @ 2026-02-01 864/week @ 2026-02-08

5,188 downloads per month
Used in 10 crates (8 directly)

MIT license

97KB
2K SLoC

human-units

Crates.io Version Docs dependency status

Size, duration and other SI units serialization and formatting library designed for configuration files and command line arguments.

Introduction

human-units is a library with Size, Duration and other SI-related types specifically designed to be used in configuration files and as command line arguments. These types serialize sizes and durations in exact but human-readable form.

The library also provides FormatSize, FormatDuration traits to print approximate values in a short human-readable form.

  • No floating point operations.
  • No dependencies by default.
  • Supports serde.
  • Supports clap.
  • Supports no_std.
  • Tested with Miri.
  • 72–85% faster than similar libraries (see benchmarks below).
  • 50–87% less binary size compared to similar libraries (see benchmarks below).

Examples

Exact human-readable size/duration

use human_units::{Duration, Size};
assert_eq!("1k", Size(1024).to_string());
assert_eq!("1025", Size(1025).to_string());
assert_eq!("1m", Duration(core::time::Duration::from_secs(60)).to_string());
assert_eq!("61s", Duration(core::time::Duration::from_secs(61)).to_string());

Inexact short human-readable size/duration

use core::time::Duration;
use human_units::{FormatDuration, FormatSize};
assert_eq!("1 KiB", 1024_u64.format_size().to_string());
assert_eq!("1 m", Duration::from_secs(60).format_duration().to_string());

Custom output

use colored::Colorize;
use core::time::Duration;
use human_units::{FormatDuration, FormattedDuration};

/// Prints the unit in cyan.
struct ColoredDuration(FormattedDuration);

impl core::fmt::Display for ColoredDuration {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        write!(f, "{}", self.0.integer)?;
        if self.0.fraction != 0 {
            write!(f, ".{}", self.0.fraction)?;
        }
        write!(f, " {}", self.0.unit.cyan())
    }
}

// prints "1 m ago", "m" is printed with cyan color
println!("{} ago", ColoredDuration(Duration::from_secs(60).format_duration()));

Serde integration

use human_units::Size;
use serde::Serialize;

#[derive(Serialize, PartialEq, Eq, Debug)]
struct SizeWrapper {
    size: Size,
}

let object = SizeWrapper{ size: Size(1024) };
assert_eq!(r#"size = "1k""#, toml::to_string(&object).unwrap().trim());

Clap integration

use clap::Parser;
use human_units::{Duration, Size};

#[derive(Parser, Debug)]
struct Args {
    #[arg(long, value_parser=clap::value_parser!(Duration))]
    timeout: Duration,
    #[arg(long, value_parser=clap::value_parser!(Size))]
    size: Size,
}

let args = Args::parse_from(["test-clap", "--timeout", "1m", "--size", "1g"]);
assert_eq!(args.timeout, Duration(core::time::Duration::from_secs(60)));
assert_eq!(args.size, Size(1024_u64.pow(3)));

SI units

use human_units::si::{Frequency, Prefix};

// Convert from hertz, internal representation is nHz (nanohertz).
let cpu_freq = Frequency::with_si_prefix(2200, Prefix::Mega);
assert_eq!("2200 MHz", cpu_freq.to_string());
assert_eq!("2.2 GHz", cpu_freq.format_si().to_string());

IEC units

use human_units::iec::{Byte, Prefix};

let size = Byte::with_iec_prefix(1536, Prefix::Kibi);
assert_eq!("1536 KiB", size.to_string());
assert_eq!("1.5 MiB", size.format_iec().to_string());

Custom units

use human_units::si::si_unit;
use human_units::iec::iec_unit;

#[si_unit(symbol = "l")]
struct Volume(pub u64);

let volume = Volume(2_200_000_000);
assert_eq!("2200 ml", volume.to_string());

#[iec_unit(symbol = "B/s")]
struct Throughput(pub u64);

let throughput = Throughput(100 * 1024);
assert_eq!("100 KiB/s", throughput.to_string());

Performance benchmarks

Benchmarks were done with Rust 1.80.1 on a x86_64 laptop.

Format size

Library Version Features Benchmark Time
human_bytes 0.4.3 fast format_size_then_to_string 88.40 ns ± 5.02 ns
human-repr 1.1.0 1024,space format_size_then_to_string 161.38 ns ± 13.29 ns
human-units 0.1.3 format_size_then_to_string 24.24 ns ± 1.23 ns

Format duration

Library Version Features Benchmark Time
human-repr 1.1.0 1024,space format_duration_then_to_string 229.47 ns ± 11.90 ns
human-units 0.1.3 format_duration_then_to_string 41.55 ns ± 2.77 ns

Executable size benchmarks

Benchmarks were done with Rust 1.80.1 on a x86_64 laptop.

Format size

Library Version Features Benchmark Executable size, B
human_bytes 0.4.3 fast print formatted size 8192
human-repr 1.1.0 1024,space print formatted size 28672
human-units 0.1.3 print formatted size 4096

Format duration

Library Version Features Benchmark Executable size, B
human-repr 1.1.0 1024,space print formatted duration 28672
human-units 0.1.3 print formatted duration 4096

Dependencies

~155KB