Humanizing Differences: Making Time Intervals More Readable with Pendulum transforms raw time deltas — seconds, minutes, days — into natural, human-friendly strings like "3 hours ago", "in 2 weeks", or "yesterday at 2:35 PM". Pendulum’s diff_for_humans() (and in_words()) method handles past/future orientation, granularity control, locale support, and localization automatically — making timestamps, logs, notifications, and user-facing dates instantly understandable. In 2026, this feature is invaluable for dashboards, chat apps, activity feeds, monitoring tools, and time-series UIs — especially when paired with Polars/pandas/Dask for columnar age calculations, FastAPI for API responses, and Pydantic for validated time deltas.
Here’s a complete, practical guide to humanizing time intervals with Pendulum: installation & basics, past/future differences, granularity & customization, locale/i18n support, real-world patterns (earthquake age display, event recency, user notifications), and modern best practices with type hints, performance, timezone awareness, and integration with Polars/pandas/Dask/FastAPI/pydantic.
1. Basic Humanization — Past, Future, and Simple Intervals
import pendulum
now = pendulum.now("UTC")
# Past events
past = now.subtract(days=3, hours=2)
print(past.diff_for_humans()) # "3 days ago"
print(past.diff_for_humans(now)) # "3 days ago"
future = now.add(hours=45, minutes=30)
print(future.diff_for_humans()) # "in 2 days"
print(future.diff_for_humans(now)) # "in 1 day and 21 hours"
# Precise control
print(past.diff_for_humans(absolute=True)) # "3 days" (no direction)
2. Granularity & Customization — Control Level of Detail
dt1 = pendulum.datetime(2026, 3, 10, 14, 35)
dt2 = pendulum.datetime(2026, 3, 15, 9, 20)
delta = dt2 - dt1
print(delta.in_words()) # "4 days 18 hours and 45 minutes"
print(delta.in_words(granularity="day")) # "5 days"
print(delta.in_words(only_distance=True)) # "4.79 days"
print(delta.in_words(locale="fr")) # "4 jours 18 heures et 45 minutes"
Real-world pattern: earthquake recency display & user notifications
import polars as pl
import pendulum
df = pl.read_csv('earthquakes.csv').with_columns(
pl.col('time').str.to_datetime(time_zone="UTC").alias('dt')
)
now = pendulum.now("UTC")
# Humanized age for each event
df = df.with_columns(
pl.col('dt').map_elements(
lambda d: pendulum.instance(d).diff_for_humans(now),
return_dtype=pl.String
).alias('recency')
)
print(df.select('time', 'mag', 'place', 'recency').head(5))
# ? "2 hours ago", "3 days ago", "last week", etc.
# Notify for recent strong quakes
recent_strong = df.filter(
(pl.col('mag') >= 7.0) & (pl.col('dt') >= now.subtract(hours=24))
)
for row in recent_strong.iter_rows(named=True):
dt = pendulum.instance(row['dt'])
print(f"ALERT: M{row['mag']:.1f} in {row['place']} — {dt.diff_for_humans(now)}")
Best practices for humanizing time with Pendulum in 2026
- Use
diff_for_humans()— for user-facing relative times ("2 hours ago", "in 3 weeks"). - Pass reference time —
dt.diff_for_humans(now)— for accurate past/future detection. - Use
in_words(granularity="...")— control detail: "hour", "day", "month", etc. - Use
only_distance=True— for neutral duration ("2.5 days"). - Support locales —
in_words(locale="fr")— i18n-ready output. - Add type hints —
from pendulum import DateTime, Duration; delta: Duration = dt1 - dt2. - Use Polars + Pendulum —
map_elements(lambda d: pendulum.instance(d).diff_for_humans(now))for columnar recency. - Use pandas + Pendulum —
df['dt'].apply(lambda d: pendulum.instance(d).diff_for_humans(now)). - Use in FastAPI — return Pendulum objects — auto JSON with ISO format.
- Use in notifications/UI —
"Event happened {dt.diff_for_humans()}". - Use
diff()— for precise breakdowns:delta.in_days(),in_hours(), etc. - Prefer aware datetimes —
pendulum.now("UTC")— for consistent calculations. - Chain methods —
dt.add(days=3).in_timezone("Asia/Tokyo").diff_for_humans(). - Use
diff_for_humans(absolute=True)— when direction is irrelevant. - Combine with
format()— for hybrid output:f"{dt.format('MMM D')} ({dt.diff_for_humans()})".
Pendulum’s humanization turns cold timestamps into warm, understandable phrases — past/future aware, locale-ready, and customizable. In 2026, use it for user-facing time, combine with Polars/pandas/Dask for scale, zoneinfo for native TZ, and type hints/Pydantic for safety. Master humanized differences, and you’ll make time intuitive and engaging in any application.
Next time you show time differences — reach for Pendulum’s diff_for_humans(). It’s Python’s cleanest way to say: “Tell the user when this happened — in words they actually understand.”