pychronotab
A modern cron expression iterator with full croniter API compatibility, supporting both 5-field (standard) and 6-field (with seconds) cron expressions.
Why pychronotab?
pychronotab was created to solve namespace conflicts when using multiple task schedulers (like django-celery-beat with python-crontab and rq-scheduler with croniter) in the same project. Both python-crontab and older cron libraries expose a top-level crontab module, causing import conflicts.
pychronotab provides:
- ✅ Zero namespace conflicts - all imports under
pychronotab - ✅ Full croniter API compatibility - drop-in replacement for abandoned croniter
- ✅ 6-field cron support - includes seconds field for sub-minute scheduling
- ✅ Modern timezone handling - uses
zoneinfo(Python 3.9+) - ✅ DST-aware - handles daylight saving time transitions correctly
- ✅ Active maintenance - not abandoned
Installation
pip install pychronotab
Quick Start
Modern API
from datetime import datetime, timezone
from pychronotab import CronExpression
# 5-field cron (standard)
expr = CronExpression("*/5 * * * *", tz=timezone.utc)
now = datetime.now(timezone.utc)
next_run = expr.next(now)
print(f"Next run: {next_run}")
# 6-field cron (with seconds)
expr_seconds = CronExpression("*/30 */5 * * * *", tz=timezone.utc)
next_run = expr_seconds.next(now)
print(f"Next run (with seconds): {next_run}")
croniter-Compatible API
Drop-in replacement for croniter (just change the import):
from datetime import datetime
from pychronotab import croniter
# Standard 5-field cron
it = croniter("*/5 * * * *", datetime.now())
print(it.get_next(datetime))
print(it.get_next(datetime))
# 6-field cron with seconds
it_seconds = croniter("*/30 */5 * * * *", datetime.now())
print(it_seconds.get_next(datetime))
Cron Expression Format
5-field format (standard Unix cron):
* * * * *
│ │ │ │ │
│ │ │ │ └─── day of week (0-6, SUN-SAT)
│ │ │ └───── month (1-12, JAN-DEC)
│ │ └─────── day of month (1-31)
│ └───────── hour (0-23)
└─────────── minute (0-59)
6-field format (with seconds):
* * * * * *
│ │ │ │ │ │
│ │ │ │ │ └─── day of week (0-6, SUN-SAT)
│ │ │ │ └───── month (1-12, JAN-DEC)
│ │ │ └─────── day of month (1-31)
│ │ └───────── hour (0-23)
│ └─────────── minute (0-59)
└───────────── second (0-59)
Supported syntax:
*- any value5- specific value1-5- range of values*/5- step values (every 5)1,3,5- list of values1-5/2- range with stepJAN-DEC,SUN-SAT- month/day names
API Reference
CronExpression (Modern API)
class CronExpression:
def __init__(self, expr: str, tz: timezone | None = None)
def next(self, base: datetime | None = None, *, inclusive: bool = False) -> datetime
def prev(self, base: datetime | None = None, *, inclusive: bool = False) -> datetime
def iter(self, start: datetime, *, direction: str = "forward", inclusive: bool = False) -> Iterator[datetime]
croniter (Compatibility API)
class croniter:
def __init__(self, expr_format: str, start_time: datetime | None = None, day_or: bool = True)
def get_next(self, ret_type: Type = datetime) -> datetime | float
def get_prev(self, ret_type: Type = datetime) -> datetime | float
def get_current(self, ret_type: Type = datetime) -> datetime | float
def all_next(self, ret_type: Type = datetime) -> Iterator[datetime | float]
def all_prev(self, ret_type: Type = datetime) -> Iterator[datetime | float]
Migration from croniter
Simply change your import:
# Old
from croniter import croniter
# New
from pychronotab import croniter
Everything else stays the same!
Avoiding Namespace Conflicts
Unlike python-crontab (which exposes crontab module) and old croniter dependencies, pychronotab keeps everything under its own namespace:
# ✅ Safe - no conflicts
from pychronotab import CronExpression, croniter
# ❌ Never exposed - won't conflict with python-crontab
# from crontab import ... # This won't exist in pychronotab
This means you can safely use:
django-celery-beat(usespython-crontab)rq-scheduler(usespychronotabinstead of abandonedcroniter)- Any other
crontab-based library
…all in the same project without import conflicts!
License
MIT License - see LICENSE file for details.
Contributing
Contributions welcome! Please open an issue or PR on GitHub.
Metadata
Release files for pychronotab 1.0.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pychronotab-1.0.7.tar.gz | 15.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pychronotab-1.0.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 27.2 kB
Release files / pychronotab-1.0.7.tar.gz
| Download URL | pychronotab-1.0.7.tar.gz |
|---|---|
| Size | 15.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
240a04167c39b4cc088c3866459a35b4b8fa0cf793d2731d706e3a0a0e8fd420
|
|
BLAKE2b-256 checksum How to use checksums |
8b6c681b1ea2b4710db3887acd74beb0a9b7862a1faeeab350f7fd8197f59aba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Release files / pychronotab-1.0.7-py3-none-any.whl
| Download URL | pychronotab-1.0.7-py3-none-any.whl |
|---|---|
| Size | 11.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8efcad54403d87a92002af0098d1d23c00de2dfada45c9de9ac97a59cddfd7b8
|
|
BLAKE2b-256 checksum How to use checksums |
ab9e5d4d5ba59563f68cf3cfb3453c370770a1bb4d220a1534c9a49bcbffddb0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|