Python datetimes made easy with timezone-aware datetime manipulation and human-readable formatting
—
Multiple output formats and localization support for human-readable datetime representation. Pendulum provides extensive formatting capabilities including standard formats, custom patterns, and localized output across 200+ languages and cultures.
Module-level functions for formatting temporal differences and managing locales.
def format_diff(
diff: Duration,
is_now: bool = True,
absolute: bool = False,
locale: str | None = None
) -> str:
"""
Format duration in human-readable form.
Parameters:
- diff: Duration to format
- is_now: Whether to include "ago"/"from now" context
- absolute: Whether to omit directional indicators
- locale: Locale for formatting
Returns:
str: Human-readable difference (e.g., "2 hours ago")
"""
def set_locale(name: str) -> None:
"""
Set global default locale.
Parameters:
- name: Locale name (e.g., 'en', 'fr', 'es', 'de')
"""
def get_locale() -> str:
"""
Get current global locale.
Returns:
str: Current locale name
"""
def locale(name: str):
"""
Get Locale instance for specific locale.
Parameters:
- name: Locale name
Returns:
Locale: Locale instance for the specified language/culture
"""Functions for configuring week start/end days globally.
def week_starts_at(wday: WeekDay) -> None:
"""
Set global week start day.
Parameters:
- wday: WeekDay enum value for week start
"""
def week_ends_at(wday: WeekDay) -> None:
"""
Set global week end day.
Parameters:
- wday: WeekDay enum value for week end
"""Methods available on DateTime instances for various output formats.
class DateTime:
def format(self, fmt: str, locale: str | None = None) -> str:
"""
Format using custom format string.
Parameters:
- fmt: Format pattern (e.g., 'YYYY-MM-DD HH:mm:ss')
- locale: Locale for formatting
Returns:
str: Formatted datetime string
"""
def for_json(self) -> str:
"""
Format for JSON serialization (ISO format).
Returns:
str: ISO 8601 formatted string
"""
def diff_for_humans(
self,
other: DateTime | None = None,
absolute: bool = False,
locale: str | None = None
) -> str:
"""
Get human-readable difference description.
Parameters:
- other: Other DateTime (defaults to now)
- absolute: Whether to omit ago/from now
- locale: Locale for formatting
Returns:
str: Human-readable difference
"""
def to_time_string(self) -> str:
"""Format as HH:mm:ss"""
def to_datetime_string(self) -> str:
"""Format as YYYY-MM-DD HH:mm:ss"""
def to_day_datetime_string(self) -> str:
"""Format as "Wed, Dec 25, 2013 4:03 PM" """
def to_atom_string(self) -> str:
"""Format as ATOM (RFC 3339)"""
def to_cookie_string(self) -> str:
"""Format for HTTP cookies"""
def to_iso8601_string(self) -> str:
"""Format as ISO 8601"""
def to_rfc822_string(self) -> str:
"""Format as RFC 822"""
def to_rfc850_string(self) -> str:
"""Format as RFC 850"""
def to_rfc1036_string(self) -> str:
"""Format as RFC 1036"""
def to_rfc1123_string(self) -> str:
"""Format as RFC 1123"""
def to_rfc2822_string(self) -> str:
"""Format as RFC 2822"""
def to_rfc3339_string(self) -> str:
"""Format as RFC 3339"""
def to_rss_string(self) -> str:
"""Format for RSS feeds"""
def to_w3c_string(self) -> str:
"""Format as W3C (ISO 8601)"""Formatting methods for Date and Time classes.
class Date:
def format(self, fmt: str, locale: str | None = None) -> str:
"""Format using custom format string"""
def to_date_string(self) -> str:
"""Format as YYYY-MM-DD"""
def to_formatted_date_string(self) -> str:
"""Format as "Dec 25, 2013" """
def diff_for_humans(
self,
other: Date | None = None,
absolute: bool = False,
locale: str | None = None
) -> str:
"""Get human-readable difference description"""
class Time:
def format(self, fmt: str, locale: str | None = None) -> str:
"""Format using custom format string"""
def diff_for_humans(
self,
other: Time | None = None,
absolute: bool = False,
locale: str | None = None
) -> str:
"""Get human-readable difference description"""Formatting methods for Duration and Interval classes.
class Duration:
def in_words(self, locale: str | None = None, separator: str = " ") -> str:
"""
Human-readable duration description.
Parameters:
- locale: Locale for formatting
- separator: Separator between components
Returns:
str: Human-readable duration
"""
class Interval(Duration):
"""Interval inherits in_words() method from Duration"""Advanced formatting and parsing capabilities.
class Formatter:
def format(
self,
dt: DateTime,
fmt: str,
locale: str | None = None
) -> str:
"""
Format datetime with pattern.
Parameters:
- dt: DateTime to format
- fmt: Format pattern
- locale: Locale for formatting
Returns:
str: Formatted string
"""
def parse(
self,
string: str,
fmt: str,
now: DateTime,
locale: str | None = None
) -> dict:
"""
Parse string with pattern.
Parameters:
- string: String to parse
- fmt: Format pattern
- now: Reference DateTime for relative parsing
- locale: Locale for parsing
Returns:
dict: Parsed components
"""Common format patterns for custom formatting:
# Date patterns
YYYY # 4-digit year (2024)
YY # 2-digit year (24)
MMMM # Full month name (January)
MMM # Short month name (Jan)
MM # 2-digit month (01)
M # Month (1)
DD # 2-digit day (01)
D # Day (1)
Do # Ordinal day (1st, 2nd)
# Time patterns
HH # 24-hour (00-23)
H # 24-hour (0-23)
hh # 12-hour (01-12)
h # 12-hour (1-12)
mm # Minutes (00-59)
m # Minutes (0-59)
ss # Seconds (00-59)
s # Seconds (0-59)
S # Deciseconds (0-9)
SS # Centiseconds (00-99)
SSS # Milliseconds (000-999)
SSSS # Microseconds (000000-999999)
A # AM/PM
a # am/pm
# Weekday patterns
dddd # Full weekday (Monday)
ddd # Short weekday (Mon)
dd # Min weekday (Mo)
d # Weekday number (1)
# Timezone patterns
Z # Offset (+05:00)
ZZ # Compact offset (+0500)
zz # Timezone name (EST)import pendulum
dt = pendulum.datetime(2024, 3, 15, 14, 30, 45, tz='Europe/Paris')
# Custom format patterns
print(dt.format('YYYY-MM-DD HH:mm:ss')) # 2024-03-15 14:30:45
print(dt.format('MMMM Do, YYYY')) # March 15th, 2024
print(dt.format('dddd, MMMM DD, YYYY')) # Friday, March 15, 2024
print(dt.format('h:mm A')) # 2:30 PM
print(dt.format('HH:mm:ss Z')) # 14:30:45 +01:00
# Localized formatting
print(dt.format('MMMM Do, YYYY', locale='fr')) # mars 15e, 2024
print(dt.format('MMMM Do, YYYY', locale='es')) # marzo 15º, 2024
print(dt.format('dddd, MMMM DD', locale='de')) # Freitag, März 15import pendulum
dt = pendulum.now('UTC')
# Standard format methods
print(dt.to_time_string()) # 14:30:45
print(dt.to_datetime_string()) # 2024-03-15 14:30:45
print(dt.to_day_datetime_string()) # Fri, Mar 15, 2024 2:30 PM
print(dt.to_iso8601_string()) # 2024-03-15T14:30:45+00:00
print(dt.to_rfc2822_string()) # Fri, 15 Mar 2024 14:30:45 +0000
print(dt.to_atom_string()) # 2024-03-15T14:30:45+00:00
# Date formatting
date = pendulum.date(2024, 3, 15)
print(date.to_date_string()) # 2024-03-15
print(date.to_formatted_date_string()) # Mar 15, 2024
# JSON serialization
print(dt.for_json()) # 2024-03-15T14:30:45+00:00import pendulum
now = pendulum.now()
# Past times
past_hour = now.subtract(hours=1)
past_day = now.subtract(days=1)
past_month = now.subtract(months=1)
print(past_hour.diff_for_humans()) # an hour ago
print(past_day.diff_for_humans()) # a day ago
print(past_month.diff_for_humans()) # a month ago
# Future times
future_hour = now.add(hours=2)
future_week = now.add(weeks=1)
print(future_hour.diff_for_humans()) # in 2 hours
print(future_week.diff_for_humans()) # in a week
# Absolute differences (no ago/from now)
print(past_hour.diff_for_humans(absolute=True)) # an hour
# Compared to specific time
yesterday = now.subtract(days=1)
print(now.diff_for_humans(yesterday)) # a day afterimport pendulum
# Set global locale
pendulum.set_locale('fr')
dt = pendulum.now().subtract(hours=2)
print(dt.diff_for_humans()) # il y a 2 heures
# Use specific locale
dt = pendulum.now().subtract(days=3)
print(dt.diff_for_humans(locale='es')) # hace 3 días
print(dt.diff_for_humans(locale='de')) # vor 3 Tagen
print(dt.diff_for_humans(locale='it')) # 3 giorni fa
# Restore English
pendulum.set_locale('en')
print(dt.diff_for_humans()) # 3 days ago
# Duration formatting with locale
duration = pendulum.duration(years=1, months=2, days=5)
print(duration.in_words()) # 1 year 2 months 5 days
print(duration.in_words(locale='fr')) # 1 an 2 mois 5 jours
print(duration.in_words(locale='es')) # 1 año 2 meses 5 díasimport pendulum
dt = pendulum.datetime(2024, 12, 25, 18, 30)
# Different locale outputs
locales = ['en', 'fr', 'es', 'de', 'it', 'pt', 'ru', 'ja', 'zh']
for loc in locales:
formatted = dt.format('MMMM Do, YYYY - dddd', locale=loc)
print(f"{loc}: {formatted}")
# Example output:
# en: December 25th, 2024 - Wednesday
# fr: décembre 25e, 2024 - mercredi
# es: diciembre 25º, 2024 - miércoles
# de: Dezember 25., 2024 - Mittwochimport pendulum
# Default week starts on Monday
dt = pendulum.date(2024, 3, 15) # Friday
week_start = dt.start_of('week')
print(f"Week starts: {week_start}") # Monday
# Change global week start to Sunday
pendulum.week_starts_at(pendulum.SUNDAY)
week_start_sunday = dt.start_of('week')
print(f"Week starts (Sunday): {week_start_sunday}") # Sunday
# Change week end
pendulum.week_ends_at(pendulum.SATURDAY)
week_end = dt.end_of('week')
print(f"Week ends: {week_end}") # Saturday
# Reset to defaults
pendulum.week_starts_at(pendulum.MONDAY)
pendulum.week_ends_at(pendulum.SUNDAY)import pendulum
formatter = pendulum.Formatter()
dt = pendulum.now()
# Direct formatting
formatted = formatter.format(dt, 'YYYY-MM-DD [at] HH:mm')
print(formatted) # 2024-03-15 at 14:30
# Parsing with format
now_ref = pendulum.now()
parsed_parts = formatter.parse('2024-12-25 18:30', 'YYYY-MM-DD HH:mm', now_ref)
print(parsed_parts) # Dict with parsed components
# Create datetime from parsed parts
if parsed_parts['tz'] is None:
parsed_parts['tz'] = 'UTC'
parsed_dt = pendulum.datetime(**parsed_parts)
print(parsed_dt)import pendulum
dt = pendulum.datetime(2024, 3, 15, 14, 30, 45, 123456)
# Combining different format elements
formats = [
'YYYY-MM-DD HH:mm:ss.SSSS', # 2024-03-15 14:30:45.1234
'ddd, MMM Do YYYY [at] h:mm A', # Fri, Mar 15th 2024 at 2:30 PM
'dddd the Do [of] MMMM, YYYY', # Friday the 15th of March, 2024
'HH:mm:ss Z [on] YYYY-MM-DD', # 14:30:45 +00:00 on 2024-03-15
'[Week] W [of] YYYY', # Week 11 of 2024
]
for fmt in formats:
print(f"{fmt:<35} → {dt.format(fmt)}")
# Literal text in square brackets
print(dt.format('[Today is] dddd')) # Today is Friday
print(dt.format('YYYY [年] MM [月] DD [日]')) # 2024 年 03 月 15 日Install with Tessl CLI
npx tessl i tessl/pypi-pendulum