croniter

Parses cron schedule strings and iterates the matching datetime values, with DST, second/year fields, and last-weekday support.

Library
PyPI
v6.2.4
566 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
74 /100 Good
Development Activity 80
Maintenance 56
Community 76
Maturity 56
Momentum 28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
75 /100 Good
Architecture 78
Code Quality 88
Innovation 80
Learning Curve 55

croniter takes a standard (or extended) cron expression and a starting datetime, then walks forward or backward to the exact moments the schedule fires. It’s the parsing and iteration engine underneath most Python scheduling code: task queues computing the next run for a periodic job, cron-expression validators in web UIs, and dashboards that need to show “next 5 runs” for a saved schedule.

Beyond the standard five-field Unix syntax, it supports optional seconds and year fields, last-day-of-month (l), nearest-weekday (W), Nth-weekday-of-month (#), hash-based expressions for spreading load across a fleet (H / @hourly-style), configurable AND/OR semantics between day-of-month and day-of-week, and DST-aware iteration when given timezone-aware datetimes.

What You Get

  • A croniter class that wraps a cron expression and a start time, exposing get_next() / get_prev() to step through matching datetimes or Unix timestamps
  • croniter.is_valid() and croniter.expand() classmethods for validating and introspecting a cron string before scheduling it, including opt-in strict=True cross-field validation (rejects impossible dates like Feb 31)
  • Extended syntax beyond POSIX cron: optional seconds and year fields, l (last day of month), W/nW (nearest weekday), # (Nth weekday of month), and hash-based expressions (H, @hourly with a hash_id) for staggering many jobs’ fire times
  • day_or and implement_cron_bug flags to control whether day-of-month and day-of-week combine with OR (POSIX default) or AND (fcron-style), including reproducing a known vixie-cron quirk for compatibility
  • Full timezone/DST awareness via zoneinfo, pytz, or dateutil.tz when a timezone-aware start_time is supplied
  • croniter_range() helper and the iterator protocol (all_next()/all_prev()) for pulling a bounded or unbounded sequence of fire times directly in a for loop

Common Use Cases

  • Computing a job’s next scheduled run inside a task queue or scheduler (Celery beat, Airflow, custom cron-like schedulers) without shelling out to system cron
  • Validating user-submitted cron expressions in a web form or admin UI before saving a scheduled job
  • Generating a preview list of upcoming run times (“next 5 executions”) for a saved schedule shown in a dashboard
  • Staggering many periodic jobs across a time window using hash-based (H) expressions so they don’t all fire at the same instant
  • Backfilling or auditing historical run times for a cron-scheduled job by iterating backward with get_prev()

Under The Hood

Architecture

croniter centers on a single croniter class (src/croniter/croniter.py, ~1,600 lines) that does two things: expand a cron expression string into per-field integer sets (_expand, feeding expanded, nth_weekday_of_month, and nearest_weekday state), then walk forward or backward from a timestamp field-by-field (proc_year/proc_month/proc_day_of_month/proc_day_of_week/proc_hour/proc_minute/proc_second closures inside _calc_next) until every field matches. A separate HashExpander class isolates the hash-based (H, @hourly) expansion logic from the core matching loop, keeping that fairly niche feature from complicating the primary code path. get_next/get_prev are thin wrappers over a shared _get_next, and all_next/all_prev turn that into a generator for the iterator protocol. The design is intentionally a single cohesive module rather than a layered system — appropriate for a focused parsing/iteration library where the field-matching state machine is the entire product.

Tech Stack

Pure Python (3.9+) with exactly one runtime dependency, python-dateutil, used for relativedelta (DST-safe date arithmetic) and tzutc/datetime_exists (DST-transition detection). No C extensions. Packaged with hatchling and uv-managed dependency groups (dev, lint, mypy, format, tox, release); tox.ini wires pytest+coverage for tests, ruff for lint and formatting, and mypy for type-checking into a single tox -e lint,mypy,fmt gate.

Code Quality

161 test functions spread across purpose-specific files (test_croniter.py, test_croniter_range.py, test_croniter_dst_repetition.py, test_croniter_hash.py, test_croniter_random.py, plus a test_croniter_speed.py performance check), run via pytest with branch coverage. A dedicated custom exception hierarchy (CroniterError, CroniterBadCronError, CroniterBadDateError, CroniterBadTypeRangeError, CroniterNotAlphaError, CroniterUnsupportedSyntaxError) replaces generic ValueErrors with specific, catchable failure modes. CI (cicd.yml) runs the lint/mypy/format gate plus the full test suite across Python 3.9 through 3.13, and a separate zizmor.yml workflow scans the GitHub Actions workflows themselves for supply-chain issues — a level of CI hygiene beyond most libraries this size.

API Design The public surface is deliberately small: construct a croniter(expr, start_time), then call get_next()/get_prev() repeatedly, or use it directly as an iterator. Sensible defaults (POSIX OR semantics, ret_type=float) mean the common case needs no keyword arguments, while power users get explicit opt-in flags (day_or, hash_id, implement_cron_bug, expand_from_start_time, second_at_beginning) for the less common behaviors. The README documents every extended feature with runnable, copy-pasteable examples rather than prose-only explanation, which keeps the learning curve low despite the fairly deep feature set (leap years, DST, hash expressions, AND/OR day semantics) hiding underneath.

Used by 15 apps in this directory

Python
60%
MIT

Foxel

File Storage

1,100

Self-hosted private cloud storage with AI semantic search and a pluggable multi-backend file management system.

View details
81
Repo Health
68
Technical
73
Dependency
Built with
Python 60%
TypeScript 37%
Updated 1 weeks ago
Python
73%
AGPL 3.0

OpenViking

AI Development · AI Memory · Databases

40,705

An open-source context database that gives AI agents a unified filesystem for memory, resources, and skills with hierarchical tiered retrieval.

View details
85
Repo Health
75
Technical
64
Dependency
Built with
Python 73%
TypeScript 12%
Rust 11%
Updated 6 days ago
Python
55%
Other

PostHog

Ab Testing Experimentation · Analytics · Developer Tools

40,397

The all-in-one open source product platform combining analytics, session replay, feature flags, error tracking, AI observability, and a built-in data warehouse in a single self-hostable stack.

View details
92
Repo Health
80
Technical
65
Dependency
Built with
Python 55%
TypeScript 36%
Updated 6 days ago
Python
79%
AGPL 3.0

Skyvern

AI Agents · Automation

23,257

Skyvern (YC S2023) automates browser-based workflows by pairing LLMs with computer vision, letting agents click, fill, and extract data on sites they've never seen, without brittle XPath selectors that break on every layout change.

View details
89
Repo Health
82
Technical
70
Dependency
Built with
Python 79%
TypeScript 19%
Updated 6 days ago
Python
71%
Apache 2.0

SurfSense

AI Assistants · Search

16,586

The open-source, unlimited NotebookLM alternative with real-time collaboration, a desktop app, and no vendor lock-in.

View details
88
Repo Health
71
Technical
66
Dependency
Built with
Python 71%
TypeScript 27%
Updated 6 days ago
Python
68%
AGPL 3.0

Tracecat

AI Agents · Automation · Security

3,860

Open-source agentic security automation platform that runs AI agents and durable workflows at scale with sandboxed execution.

View details
89
Repo Health
88
Technical
66
Dependency
Built with
Python 68%
TypeScript 30%
Updated 6 days ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers