A cron expression iterator with croniter-compatible API, supporting 5 and 6-field cron (with seconds). Named after Chronos (time) to avoid conflicts with crontab packages.
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pychronotab-1.0.0.tar.gz.
File metadata
- Download URL: pychronotab-1.0.0.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45ba673aac5c565e397009b80365b85c9d11a0135e9944db93bdb48f223e7e25
|
|
| MD5 |
1ce0af789072a1352110b2eec27483e2
|
|
| BLAKE2b-256 |
200268e5878b60bf4f580a1c23ea08a7e6bc24e2e81deae9f8af516931a6ab51
|
File details
Details for the file pychronotab-1.0.0-py3-none-any.whl.
File metadata
- Download URL: pychronotab-1.0.0-py3-none-any.whl
- Upload date:
- Size: 11.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b873148057d420b842305df50fe1390e1b01eb0fe297f201dedc713a41157499
|
|
| MD5 |
b400fab239c25b3f7ce9862850469c38
|
|
| BLAKE2b-256 |
a38527811aad95b5de8134600a957e2579a72c8de2ed16947dfa0ea0fd5c8ece
|