pendulum
A drop-in replacement for Python's datetime with timezone-aware objects by default and a friendlier API.
Repository Health
Technical Analysis
Pendulum subclasses the standard library’s datetime so it behaves as a drop-in replacement while removing the notion of naive datetimes: every instance is timezone-aware, defaulting to UTC. It adds fluent methods for adding, subtracting, and comparing dates, human-readable diffs like “2 minutes ago,” and correct handling of DST transitions and timezone normalization edge cases that trip up the raw standard library.
Parsing and low-level date arithmetic are implemented in a Rust extension (built with PyO3/maturin) for speed, with a pure-Python fallback, so the library stays fast without sacrificing the readable, chainable API it’s known for. It also improves on timedelta with a Duration class offering in_words, in_hours, and similar intuitive accessors, plus a testing module for freezing or traveling through time in tests.
What You Get
- Timezone-aware by default - every
DateTimecreated viapendulum.now()orpendulum.datetime()carries a timezone (UTC unless specified), eliminating an entire class of naive-datetime bugs. - Fluent date arithmetic - chainable
.add(),.subtract(),.in_timezone(), and comparison helpers that read like English instead oftimedeltajuggling. - Human-readable diffs -
diff_for_humans()renders relative time like “2 minutes ago” or “in 3 days”, with locale support for many languages. - Correct DST and normalization handling - operations across daylight-saving transitions and ambiguous/skipped local times resolve predictably instead of silently producing wrong wall-clock values.
- Rust-accelerated parsing - ISO 8601 and common date-string parsing is implemented in a Rust extension via PyO3 for speed, transparent to callers.
- Time-travel testing utilities - the
pendulum.testingmodule lets tests freezependulum.now()or travel to arbitrary points in time without monkeypatching.
Common Use Cases
- Scheduling and cron-like logic - computing “next occurrence” or recurring intervals across timezones without DST bugs.
- API and log timestamps - parsing and formatting ISO 8601 timestamps from external services consistently, in UTC or a target timezone.
- User-facing relative timestamps - showing “5 minutes ago” style text in dashboards or activity feeds via
diff_for_humans(). - Multi-timezone applications - converting and displaying the same moment in time correctly across users in different timezones.
- Time-dependent test suites - freezing or traveling the clock in unit tests with
pendulum.testinginstead of mockingdatetime.now.
Under The Hood
Architecture
The public API is assembled in src/pendulum/__init__.py, which re-exports the core Date, DateTime, Time, Duration, and Interval classes along with module-level factory functions (now(), parse(), datetime(), timezone()). DateTime (in datetime.py, ~1400 lines) subclasses both datetime.datetime and the library’s own Date mixin, layering fluent methods (add, subtract, in_timezone, diff_for_humans) on top of the standard interface so existing code that type-checks against datetime.datetime keeps working. Timezone resolution lives in tz/timezone.py and tz/local_timezone.py, string parsing in parsing/iso8601.py, and output formatting in formatting/formatter.py and formatting/difference_formatter.py — a clean separation between representation, timezone logic, and parsing/formatting concerns. A testing/traveller.py module implements clock-freezing/travel by substituting the module-level now() used internally, letting test suites control time without patching the standard library.
Tech Stack
The project is a hybrid Python/Rust package built with maturin and PyO3 (rust/ directory, exposed as the pendulum._pendulum extension module declared in pyproject.toml’s [tool.maturin] section), giving performance-sensitive parsing and helper routines a compiled fast path while the public API stays pure Python. Runtime dependencies are minimal — python-dateutil and tzdata — keeping the install footprint small. Tooling is modern Python: ruff for linting and import sorting, mypy --strict for type checking (with a shrinking legacy-exclusion allowlist), and Poetry-managed dependency groups for test, doc, lint, typing, dev, and benchmark concerns.
Code Quality
The tests/ tree mirrors the source layout with dedicated suites per concern (date/, datetime/, duration/, interval/, time/, tz/, parsing/, formatting/, localization/, plus dedicated thread-safety and benchmark suites), run with pytest and pytest-benchmark/pytest-codspeed for performance regression tracking. Type hints are comprehensive with a py.typed marker and mypy --strict enforcement, and CI (.github/workflows/tests.yml) runs the suite across supported Python versions. Naming and structure are consistent throughout, and ruff enforces both style and a set of correctness-oriented lint rules (bugbear, comprehensions, simplify) rather than formatting alone.
What Makes It Unique
Pendulum’s defining choice is being a strict subclass of datetime.datetime rather than a wrapper class — it can be passed anywhere a standard datetime is expected, which most “nicer datetime” libraries can’t claim. Combining that compatibility with mandatory timezone-awareness (no naive datetimes exist in the API) and DST-correct arithmetic addresses a class of bugs the standard library leaves as footguns. Offloading parsing to a Rust extension while keeping the ergonomic Python surface unchanged is a pragmatic response to Python datetime libraries’ historical performance complaints, without asking users to learn a different API.
Used by 4 apps in this directory
Airbyte
Developer Tools · Data Engineering
Open-source ELT platform with 600+ connectors for moving data from any source to warehouses, lakes, and AI agents.
Apache Airflow
Data Engineering
Define, schedule, and monitor complex data workflows as Python code — with a powerful UI, 80+ provider integrations, and battle-tested scalability across thousands of production deployments.
Flowfile
Data Engineering
Visual ETL that compiles to Polars — build pipelines on a canvas, export as standalone Python, and run anywhere without platform lock-in.
PostgresML
Databases · AI Development
Run ML training and LLM inference natively inside PostgreSQL with GPU acceleration — no data movement required.