Human-friendly formatting helpers for Elixir.
A small, flat set of pure functions that turn raw values into the kind of strings you show to people:
bytes/2—2_456_789→"2.5 MB"duration/2—3725→"1 hour, 2 minutes"relative_time/3— aDateTime→"2 days ago"number/2—1_234_567→"1.2M"ordinal/1—23→"23rd"list_join/2—["Alice", "Bob", "Charlie"]→"Alice, Bob and Charlie"
Design
- English only. No localization in v0.1. For real i18n use
ex_cldr. - No global config. Every option is a keyword passed to the function.
- One rounding rule. Decimal output uses round-half-away-from-zero with a
single fractional digit by default (
:precisionto override). - No scientific notation, ever. Numbers are formatted from integers, so
values up to
10 ** 15never come out as"1.0e15".
Summary
Functions
Formats a byte count as a human-readable size.
Formats a duration given in seconds as words.
Joins a list of strings into a human-readable enumeration.
Formats a number with a magnitude suffix (K, M, B, T).
Returns the integer with its English ordinal suffix.
Formats a DateTime relative to now (or to a given reference time).
Functions
@spec bytes( non_neg_integer(), keyword() ) :: String.t()
Formats a byte count as a human-readable size.
Uses decimal (SI, base 1000) units by default. Pass system: :binary for
IEC (base 1024) units. Precision defaults to one fractional digit.
Options
:system—:decimal(default) or:binary:precision— number of fractional digits (default1)
Examples
iex> Humanizer.bytes(2_456_789)
"2.5 MB"
iex> Humanizer.bytes(2_456_789, system: :binary)
"2.3 MiB"
iex> Humanizer.bytes(2_456_789, precision: 2)
"2.46 MB"
iex> Humanizer.bytes(0)
"0 B"
Formats a duration given in seconds as words.
Breaks the duration down into days, hours, minutes and seconds (months and years are out of scope in v0.1). By default the two most significant non-zero units are shown.
Options
:units— number of units to show, or:all(default2):format—:long(default,"1 hour") or:short("1h")
Raises ArgumentError for negative input.
Examples
iex> Humanizer.duration(3725)
"1 hour, 2 minutes"
iex> Humanizer.duration(3725, units: 1)
"1 hour"
iex> Humanizer.duration(3725, units: :all)
"1 hour, 2 minutes, 5 seconds"
iex> Humanizer.duration(45, format: :short)
"45s"
Joins a list of strings into a human-readable enumeration.
Options
:conjunction— word before the last item (default"and"):oxford— add a serial comma before the conjunction (defaultfalse). Has no effect on two-item lists.
Examples
iex> Humanizer.list_join(["Alice", "Bob", "Charlie"])
"Alice, Bob and Charlie"
iex> Humanizer.list_join(["Alice", "Bob"])
"Alice and Bob"
iex> Humanizer.list_join(["Alice", "Bob", "Charlie"], oxford: true)
"Alice, Bob, and Charlie"
iex> Humanizer.list_join(["Alice", "Bob", "Charlie"], conjunction: "or")
"Alice, Bob or Charlie"
Formats a number with a magnitude suffix (K, M, B, T).
Accepts integers and floats, positive or negative. Values below 1000 are
rendered without a suffix or decimals. The ceiling in v0.1 is trillions (T).
Options
:precision— number of fractional digits for suffixed values (default1)
Examples
iex> Humanizer.number(1_234)
"1.2K"
iex> Humanizer.number(1_234_567)
"1.2M"
iex> Humanizer.number(999)
"999"
iex> Humanizer.number(-1_234, precision: 2)
"-1.23K"
Returns the integer with its English ordinal suffix.
Correctly handles the 11/12/13 exceptions and negative numbers.
Examples
iex> Humanizer.ordinal(1)
"1st"
iex> Humanizer.ordinal(11)
"11th"
iex> Humanizer.ordinal(23)
"23rd"
iex> Humanizer.ordinal(-1)
"-1st"
@spec relative_time( DateTime.t(), keyword() ) :: String.t()
Formats a DateTime relative to now (or to a given reference time).
Past times read as "X ago", future times as "in X", and anything within a
minute as "just now". Both arguments are compared as absolute instants, so
time zones are handled correctly. The largest unit is days (v0.1).
Examples
iex> Humanizer.relative_time(~U[2026-05-13 10:00:00Z], ~U[2026-05-15 10:00:00Z])
"2 days ago"
iex> Humanizer.relative_time(~U[2026-05-15 13:00:00Z], ~U[2026-05-15 10:00:00Z])
"in 3 hours"
iex> Humanizer.relative_time(~U[2026-05-15 10:00:00Z], ~U[2026-05-15 10:00:00Z])
"just now"
@spec relative_time(DateTime.t(), DateTime.t(), keyword()) :: String.t()