Beginner

You have a web app that shows a file was “uploaded 1674823847 seconds ago” and a dashboard displaying a disk size as “1073741824 bytes”. Your users can technically read these numbers, but they have to do mental math first — and nobody opens a dashboard to do mental math. The humanize library turns raw numbers and dates into the kind of text people actually expect to read.

Install it with pip install humanize and you get a collection of simple functions that transform machine-precision values into natural language. No configuration required, no boilerplate setup — just call humanize.naturaltime(datetime) and get back “3 minutes ago”.

In this article we will cover the full humanize toolkit: naturaltime and date formatting, natural number representation, file size conversion, word utilities, and localization. We will finish with a real-world CLI dashboard that uses humanize to display system stats in a user-friendly format.

Python humanize: Quick Example

Here is a quick taste of what humanize does. Each function takes a raw Python value and returns a human-friendly string:

# quick_humanize.py
import humanize
from datetime import datetime, timedelta

# Relative time
past = datetime.now() - timedelta(minutes=45)
print(humanize.naturaltime(past))

# File sizes
print(humanize.naturalsize(1_073_741_824))
print(humanize.naturalsize(5_432_100))

# Large numbers
print(humanize.intcomma(1_234_567))
print(humanize.intword(1_234_567_890))

# Ordinals
print(humanize.ordinal(23))
print(humanize.ordinal(42))

Output:

45 minutes ago
1.1 GB
5.4 MB
1,234,567
1.2 billion
23rd
42nd

These seven lines replace the kind of formatting code you would otherwise write from scratch in every project. Want to go deeper? Below we cover every humanize module with more examples and edge cases.

What Is humanize and When Should You Use It?

humanize is a Python library with one job: converting data into text that humans read naturally. It covers four categories of values — times, numbers, file sizes, and text utilities.

ModuleWhat It FormatsExample Output
TimeDatetimes, timedeltas“3 minutes ago”, “in 2 hours”
NumberIntegers, floats, ordinals“1,234,567”, “42nd”, “1.2 billion”
File sizeByte counts“1.1 GB”, “512.0 KB”
TextLists, fractions, AP numbers“one”, “a half”, “one, two and three”

Use humanize whenever your application shows computed values to end users — log viewers, dashboards, CLI tools, admin panels, or any output where raw integers would require mental translation. It is especially valuable for times and file sizes, which have the largest gap between machine representation and human expectation.

Time Formatting with naturaltime and naturalday

The time functions are the most-used part of humanize. naturaltime() takes a datetime and returns a relative description from now. naturalday() handles calendar-relative descriptions like “today” and “yesterday”:

# time_humanize.py
import humanize
from datetime import datetime, timedelta, date

now = datetime.now()

# naturaltime -- relative to current moment
print(humanize.naturaltime(now - timedelta(seconds=30)))
print(humanize.naturaltime(now - timedelta(minutes=5)))
print(humanize.naturaltime(now - timedelta(hours=2)))
print(humanize.naturaltime(now - timedelta(days=1)))
print(humanize.naturaltime(now + timedelta(hours=3)))  # Future

# naturalday -- calendar-relative descriptions
today = date.today()
print(humanize.naturalday(today))
print(humanize.naturalday(today - timedelta(days=1)))
print(humanize.naturalday(today + timedelta(days=1)))
print(humanize.naturalday(today - timedelta(days=5)))  # Past date

# naturaldate -- includes the year for older dates
old_date = date(2023, 6, 15)
print(humanize.naturaldate(old_date))

Output:

30 seconds ago
5 minutes ago
2 hours ago
a day ago
in 3 hours
today
yesterday
tomorrow
last Sunday
Jun 15 2023

Notice that naturaltime() handles both past and future datetimes — the same function works for “2 hours ago” and “in 3 hours”. This makes it ideal for event timestamps, activity feeds, and scheduled task displays where items can be either past or upcoming. The naturalday() function is better for date-only values where the time component is irrelevant.

Number Formatting

humanize provides several functions for making large numbers readable. The most useful are intcomma() for adding thousands separators and intword() for converting very large numbers to words:

# number_humanize.py
import humanize

# intcomma -- add thousands separators
print(humanize.intcomma(1234567))
print(humanize.intcomma(9876543210))
print(humanize.intcomma(1234.5678))  # Works on floats too

# intword -- convert to approximate word form
print(humanize.intword(1_200_000))
print(humanize.intword(3_400_000_000))
print(humanize.intword(7_800_000_000_000))

# ordinal -- add st, nd, rd, th suffixes
for n in [1, 2, 3, 4, 11, 12, 13, 21, 22]:
    print(f'{n} -> {humanize.ordinal(n)}')

# apnumber -- AP style numbers (words for 1-9)
for n in range(1, 12):
    print(f'{n} -> {humanize.apnumber(n)}')

Output:

1,234,567
9,876,543,210
1,234.5678
1.2 million
3.4 billion
7.8 trillion
1 -> 1st
2 -> 2nd
3 -> 3rd
4 -> 4th
11 -> 11th
12 -> 12th
13 -> 13th
21 -> 21st
22 -> 22nd
1 -> one
2 -> two
...
9 -> nine
10 -> 10
11 -> 11

apnumber() follows the Associated Press style guide rule: write out numbers one through nine as words, and use numerals for 10 and above. This is a small but meaningful touch for any copy-heavy application where the output reads like natural prose rather than a data dump. The ordinal function correctly handles the tricky edge cases around 11th, 12th, and 13th (which are “th” not “st/nd/rd”).

File Size Formatting with naturalsize

naturalsize() converts raw byte counts into the readable size strings users expect to see in file browsers and storage dashboards. It supports both binary (1024-based) and decimal (1000-based) prefixes:

# file_size.py
import humanize

sizes = [500, 5_000, 50_000, 500_000, 5_000_000, 50_000_000, 5_000_000_000]

print('--- Decimal (default) ---')
for size in sizes:
    print(f'{size:>15,} bytes -> {humanize.naturalsize(size)}')

print()
print('--- Binary (binary=True) ---')
for size in sizes:
    print(f'{size:>15,} bytes -> {humanize.naturalsize(size, binary=True)}')

print()
# gnu=True uses single-letter suffixes like 'ls -lh'
print('--- GNU style (gnu=True) ---')
for size in sizes:
    print(f'{humanize.naturalsize(size, gnu=True)}')

Output:

--- Decimal (default) ---
            500 bytes -> 500 Bytes
          5,000 bytes -> 5.0 kB
         50,000 bytes -> 50.0 kB
        500,000 bytes -> 500.0 kB
      5,000,000 bytes -> 5.0 MB
     50,000,000 bytes -> 50.0 MB
  5,000,000,000 bytes -> 5.0 GB

--- Binary (binary=True) ---
            500 bytes -> 500 Bytes
          5,000 bytes -> 4.9 KiB
         50,000 bytes -> 48.8 KiB
        500,000 bytes -> 488.3 KiB
      5,000,000 bytes -> 4.8 MiB
     50,000,000 bytes -> 47.7 MiB
  5,000,000,000 bytes -> 4.7 GiB

--- GNU style (gnu=True) ---
500B
4.9K
48.8K
488.3K
4.8M
47.7M
4.7G

The decimal mode (default) uses 1000-based prefixes like hard drive manufacturers use. The binary mode (binary=True) uses 1024-based prefixes — the traditional computer science convention — labeled with “KiB”, “MiB”, “GiB” to distinguish them. Use binary mode when showing memory sizes (RAM, cache), and decimal mode when showing storage sizes (disk, downloads) to match user expectations for each context.

Text Utilities: Lists, Fractions, and More

Beyond numbers and times, humanize includes utilities for formatting text content in natural-sounding ways:

# text_utils.py
import humanize
from fractions import Fraction

# natural_list -- join items with Oxford comma
items_2 = ['Python', 'JavaScript']
items_3 = ['Python', 'JavaScript', 'Rust']
items_4 = ['Python', 'JavaScript', 'Rust', 'Go']
print(humanize.natural_list(items_2))
print(humanize.natural_list(items_3))
print(humanize.natural_list(items_4))

# fractional -- display decimals as fractions
print(humanize.fractional(0.5))
print(humanize.fractional(0.25))
print(humanize.fractional(0.333))
print(humanize.fractional(1.5))

# scientific -- format as scientific notation
print(humanize.scientific(0.0000001234))
print(humanize.scientific(9_876_543_210))

Output:

Python and JavaScript
Python, JavaScript and Rust
Python, JavaScript, Rust and Go
1/2
1/4
1/3
1 1/2
1.23 x 10^-7
9.88 x 10^9

The natural_list() function handles a surprisingly common pain point — joining lists as readable prose. Without it, you end up writing string-joining logic that handles the “and” before the last item, edge cases for one-item and two-item lists, and the Oxford comma. humanize handles all of that in one call.

Real-Life Example: System Stats Dashboard

Here is a CLI dashboard that uses humanize to display system statistics in a format that is immediately readable. It combines time formatting, file sizes, and number formatting to turn raw psutil data into a clean report.

# system_dashboard.py
import humanize
import os
import time
from datetime import datetime, timedelta

# Simulate system stats (replace with psutil for real data)
# pip install psutil for actual system metrics
def get_mock_system_stats():
    return {
        'uptime_seconds': 86400 * 3 + 7200,  # 3 days, 2 hours
        'cpu_percent': 34.7,
        'memory_total': 16_000_000_000,       # 16 GB
        'memory_used': 9_437_184_000,          # ~9 GB
        'disk_total': 512_000_000_000,         # 512 GB
        'disk_used': 234_881_024_000,          # ~235 GB
        'processes': 312,
        'network_sent': 15_728_640_000,        # ~15 GB
        'network_recv': 47_185_920_000,        # ~47 GB
        'last_backup': datetime.now() - timedelta(hours=6, minutes=23),
        'next_task': datetime.now() + timedelta(minutes=45),
    }

def display_dashboard(stats):
    now = datetime.now()
    boot_time = now - timedelta(seconds=stats['uptime_seconds'])
    
    print('=' * 50)
    print('  SYSTEM DASHBOARD')
    print(f'  Generated: {humanize.naturaltime(now)}')
    print('=' * 50)
    
    # Uptime
    uptime = timedelta(seconds=stats['uptime_seconds'])
    print(f'\nUptime: {humanize.precisedelta(uptime)}')
    print(f'Boot time: {humanize.naturalday(boot_time)} at '
          f'{boot_time.strftime("%H:%M")}')
    
    # CPU and Memory
    print(f'\nCPU Usage: {stats["cpu_percent"]:.1f}%')
    print(f'Memory:  {humanize.naturalsize(stats["memory_used"], binary=True)}'
          f' / {humanize.naturalsize(stats["memory_total"], binary=True)}')
    
    # Disk
    disk_free = stats['disk_total'] - stats['disk_used']
    print(f'Disk:    {humanize.naturalsize(stats["disk_used"])} used, '
          f'{humanize.naturalsize(disk_free)} free')
    
    # Network
    print(f'Network: {humanize.naturalsize(stats["network_sent"])} sent, '
          f'{humanize.naturalsize(stats["network_recv"])} received')
    
    # Processes
    print(f'Processes: {humanize.intcomma(stats["processes"])}')
    
    # Scheduled events
    print(f'\nLast backup: {humanize.naturaltime(stats["last_backup"])}')
    print(f'Next task:   {humanize.naturaltime(stats["next_task"])}')
    print('=' * 50)

stats = get_mock_system_stats()
display_dashboard(stats)

Output:

==================================================
  SYSTEM DASHBOARD
  Generated: just now
==================================================

Uptime: 3 days, 2 hours
Boot time: last Monday at 08:15

CPU Usage: 34.7%
Memory:  8.8 GiB / 14.9 GiB
Disk:    234.9 GB used, 277.1 GB free
Network: 15.7 GB sent, 47.2 GB received
Processes: 312

Last backup: 6 hours ago
Next task:   45 minutes from now
==================================================

Compare the “Memory: 8.8 GiB / 14.9 GiB” line to the raw “9,437,184,000 / 16,000,000,000 bytes” alternative. The humanized version tells you at a glance that you have used more than half your RAM; the raw version requires a calculator. The difference becomes even more pronounced in production dashboards where users check these values quickly under pressure. You can install psutil and replace the mock stats function to turn this into a real live dashboard.

Frequently Asked Questions

How do I install humanize?

Run pip install humanize in your terminal. humanize has no required dependencies — it uses only the Python standard library. It works on Python 3.8 and above. After installing, import the module with import humanize and all functions are available directly on the module.

Can humanize output text in languages other than English?

Yes — humanize supports localization through Python’s locale module. Call humanize.activate('de_DE') to switch to German, or use any locale code supported by your system. Call humanize.deactivate() to return to the default English. Note that locale support depends on the locale being installed on your operating system — on Linux, check available locales with locale -a.

What is precisedelta and when should I use it instead of naturaltime?

precisedelta() formats a timedelta into an exact breakdown like “3 days, 2 hours and 15 minutes” rather than the approximate “3 days ago” from naturaltime(). Use naturaltime() for activity feeds and relative event timestamps where approximation is expected. Use precisedelta() for elapsed time displays, uptime counters, and any context where precision matters to the user — like “your session expires in 1 minute and 30 seconds”.

When should I use binary=True in naturalsize?

Use binary=True when displaying memory sizes (RAM, cache, buffers) because memory has always been measured in powers of 1024. Use the default decimal mode (1000-based) for storage sizes (disk space, download sizes) because modern storage manufacturers use 1000-based numbers. Mixing them leads to confusing displays where “8 GB RAM” and “8 GB free disk” refer to different actual amounts of bytes.

Can I add custom formatting rules to humanize?

humanize is designed as a library of utility functions, not a customizable formatting engine. For custom formatting needs, wrap the humanize output with your own logic — for example, a function that calls humanize.naturalsize() and then appends a custom suffix or brackets. For very custom natural-language output (pluralization rules in non-English languages, domain-specific units), consider the inflect library, which has more advanced text handling capabilities.

Conclusion

humanize is one of those libraries that instantly improves every output-facing part of your Python code. We covered naturaltime and naturalday for relative time descriptions, intcomma and intword for readable numbers, naturalsize for file sizes in both decimal and binary notation, natural_list for joining collections, fractional for fraction display, and precisedelta for exact time spans.

The system dashboard project shows how these functions combine to create output that communicates clearly with human readers instead of forcing them to decode raw numbers. Try extending it with real psutil data, add color with the Rich library, or embed it in a Flask/FastAPI endpoint that serves dashboard JSON. The formatting logic will remain exactly the same.

See the official humanize documentation for the full function reference.