CronDelta
Compare actual cron engines before changing the library behind your schedules.
Changing a cron library, its version, or its options can change when a schedule fires. CronDelta calls two installed Python engines and compares their UTC occurrences in a finite window. It reports the first proven difference, the versions and timezone data used, and whether the window was fully checked.
Quick start
Use Python 3.11+ and uv. Install the released CLI from PyPI. If the release is not yet available there, use the source installation below.
uv tool install crondelta==0.1.0
crondelta compare \
--left-engine croniter --left-version 6.2.4 \
--right-engine apscheduler --right-version 3.11.3 \
--expression '0 9 1 * mon' --timezone UTC \
--start 2026-10-01T00:00:00Z --end 2026-11-01T00:00:00Z
This returns DIFFERENT, with exit code 1. Croniter's default
day-of-month/day-of-week OR rule yields October 1, 5, 12, 19, and 26 at 09:00 UTC.
APScheduler's AND rule yields no occurrences in that window. The first witness
is October 1 at 09:00 UTC versus a fully checked empty right-hand stream.
Changing the expression to 0 9 * * mon returns MATCH_WITHIN_WINDOW, with
exit code 0. This means the streams match throughout the checked
[start, end) window; it makes no claim about dates outside that window.
A difference can reflect an intentional library contract.
For JSON output, add --format json. For multiple schedules, download the
migration manifest
and save it as migration.json in your current directory, then run:
crondelta compare --manifest migration.json --format json
The installed CLI does not include example manifests. More example manifests are in the repository. To build and install from source instead:
git clone https://github.com/0then0/crondelta.git
cd crondelta
uv build
uv tool install ./dist/crondelta-0.1.0-py3-none-any.whl
crondelta --version
Installation prepares dependencies. Running compare uses already available
interpreters and libraries; it never installs packages, creates environments,
executes jobs, or connects to a database.
Supported comparisons
- Engines: croniter and APScheduler 3.x
CronTrigger, using their public APIs. The locked baseline is croniter 6.2.4, APScheduler 3.11.3, and tzdata 2026.2. Historical UTC controls cover croniter 6.0.0 and APScheduler 3.11.2. Other installed versions can be requested explicitly. - Profiles: independent expressions, supported options, exact version requirements, and Python interpreters. This also supports comparing two versions of the same engine. Each target interpreter needs its engine and tzdata installed; it does not need a separate CronDelta installation.
- Expressions: five fields: minute, hour, day-of-month, month, day-of-week. Six/seven fields, aliases, random/hash fields, and APScheduler 4.x are outside v0.1 scope. Each engine parses its own expression.
- Timezones: an explicit IANA key, with both engines forced to use the tzdata wheel. Reports record its version and the timezone file's SHA-256. Comparing different timezone databases is outside v0.1 scope.
- Evidence: exact UTC datetimes, original local time, offset, fold, and UTC
round-trip. Deadlines and output/occurrence limits bound enumeration. An
incomplete calculation cannot produce
MATCH_WITHIN_WINDOW.
CronDelta checks trigger calculations. Scheduler execution policies such as misfires, coalescing, jitter, and catch-up are outside its scope. It does not convert expressions or repair migrations automatically.
Documentation
- CLI reference: profiles, manifests, limits, exit codes, and interpreting incomplete results.
- Report and adapter protocol: JSON fields, evidence, and the enumeration contract, including start boundaries and DST.
- query-exporter migration case study: pinned upstream sources, controlled differences, and reproduction commands.
- Testing and support: verification commands, CI matrix, and tested behavior.
- Example manifests and representative JSON reports.
Related tools
cron-utils provides Java parsing, validation, dialect mapping, and execution-time calculations. cronkit provides cron humanization, inventories, auditing, timelines, and crontab diffs. cron-comparison compares and benchmarks JavaScript cron implementations against fixtures. CronDelta focuses on two installed Python profiles and reproducible evidence for a specific time window.
Development
From a checkout:
uv sync --locked
uv run crondelta --version
sh scripts/verify.sh
This runs linting, tests, wheel/sdist builds, installed-package checks, and reproduction controls. See Testing and support for details.
Licensed under Apache-2.0.
Metadata
Release files for crondelta 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| crondelta-0.1.0.tar.gz | 60.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| crondelta-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 82.3 kB
Release files / crondelta-0.1.0.tar.gz
| Download URL | crondelta-0.1.0.tar.gz |
|---|---|
| Size | 60.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
34591a35f2d38b19f768bec97bcf30465f76087f8edd3e23e269094e3badca0f
|
|
BLAKE2b-256 checksum How to use checksums |
0e901e063f2dc80704dc3c7f814f5116890f630a0342bd10fdaf1977220aea94
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / crondelta-0.1.0-py3-none-any.whl
| Download URL | crondelta-0.1.0-py3-none-any.whl |
|---|---|
| Size | 22.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e61a954cfeff18f1d1155b34323155582112c1cb0730943f44e9ee475091be57
|
|
BLAKE2b-256 checksum How to use checksums |
4f6f91386c77b275195c40f5abbdc468aafaeda4cf35dc48b7c3952d94f15f9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency log