Cron expression parser with human-readable descriptions and next-run calculation
Project description
cron-parser-py
Cron expression parser with human-readable descriptions and next-run calculation.
Pure Python · Zero dependencies · Python 3.9+
from cron_parser_py import CronParser
expr = CronParser.parse("0 9 * * MON-FRI")
print(expr.description()) # At 9:00 AM, Monday through Friday
print(expr.next_run()) # 2024-01-15 09:00:00
print(expr.next_runs(3)) # [datetime, datetime, datetime]
Installation
pip install cron-parser-py
Features
| Capability | Details |
|---|---|
| 5-field standard cron | MIN HOUR DOM MON DOW |
| 6-field (with seconds) | SEC MIN HOUR DOM MON DOW |
| 7-field (with year) | SEC MIN HOUR DOM MON DOW YEAR |
| Predefined macros | @yearly, @monthly, @weekly, @daily, @hourly, @reboot |
| Special characters | * / , - ? L W # |
| Name aliases | JAN–DEC, SUN–SAT (case-insensitive) |
| Human descriptions | Natural English for any expression |
| Next / previous run | Forward and backward time search |
is_due check |
Determine if an expression fires right now |
| Validation | Detailed error messages with field/value context |
Quick start
Module-level helpers
import cron_parser_py as cron
# Human-readable description
cron.describe("*/5 * * * *") # "Every 5 minutes"
cron.describe("0 9 * * MON-FRI") # "At 9:00 AM, Monday through Friday"
cron.describe("0 0 1 1 *") # "At midnight, on the 1st, in January"
# Validate without raising
cron.is_valid("0 9 * * MON-FRI") # True
cron.is_valid("99 9 * * *") # False
# Next run time
cron.next_run("0 * * * *") # next top-of-hour datetime
# Multiple next runs
cron.next_runs("*/15 * * * *", 5) # list of 5 datetimes
# Previous run
cron.previous_run("0 0 * * *") # most recent midnight
# Is due right now?
cron.is_due("* * * * *") # True (every minute)
CronExpression object
from cron_parser_py import CronParser
expr = CronParser.parse("30 8 * * 1-5")
expr.description() # "At 8:30 AM, Monday through Friday"
expr.next_run() # next scheduled datetime
expr.next_runs(count=10) # list of next 10 datetimes
expr.previous_run() # most recent past run
expr.is_due() # True/False right now
str(expr) # "30 8 * * 1-5"
Supported syntax
Field positions
Standard 5-field:
┌──────── minute (0–59)
│ ┌────── hour (0–23)
│ │ ┌──── day-of-month (1–31)
│ │ │ ┌── month (1–12)
│ │ │ │ ┌ day-of-week (0–7, 0 and 7 = Sunday)
* * * * *
6-field (add seconds at the front):
┌──────────── second (0–59)
│ ┌────────── minute (0–59)
│ │ ┌──────── hour (0–23)
│ │ │ ┌────── day-of-month (1–31)
│ │ │ │ ┌──── month (1–12)
│ │ │ │ │ ┌── day-of-week (0–6)
* * * * * *
Special characters
| Character | Meaning | Example |
|---|---|---|
* |
every value | * * * * * — every minute |
? |
any (day fields only) | 0 0 ? * 1 — every Monday |
/ |
step | */15 * * * * — every 15 min |
- |
range | MON-FRI |
, |
list | 1,15 * * * — 1st and 15th |
L |
last | L in DOM — last day of month |
W |
nearest weekday | 15W — nearest weekday to 15th |
LW |
last weekday | last weekday of month |
# |
Nth weekday | 5#2 — second Friday |
nL |
last Nth weekday | 5L — last Friday |
Month and weekday names
JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
SUN MON TUE WED THU FRI SAT
Names are case-insensitive and can be used in ranges: MON-FRI.
Predefined macros
| Macro | Equivalent | Description |
|---|---|---|
@yearly / @annually |
0 0 1 1 * |
Once a year, on Jan 1st at midnight |
@monthly |
0 0 1 * * |
Once a month, on the 1st at midnight |
@weekly |
0 0 * * 0 |
Once a week, on Sunday at midnight |
@daily / @midnight |
0 0 * * * |
Every day at midnight |
@hourly |
0 * * * * |
Every hour |
@reboot |
— | At system startup |
API Reference
CronParser
CronParser.parse(expression: str) -> CronExpression
Parse a cron expression string. Raises CronParseError on failure.
CronParser.is_valid(expression: str) -> bool
Return True if the expression is parseable without errors.
CronExpression
| Method | Returns | Description |
|---|---|---|
.description() |
str |
Human-readable English description |
.next_run(from_time=None) |
datetime |
Next run after from_time (default: now) |
.next_runs(count=5, from_time=None) |
list[datetime] |
Next N run times |
.previous_run(from_time=None) |
datetime |
Most recent run before from_time |
.is_due(at_time=None, tolerance_seconds=0) |
bool |
True if expression fires now |
str(expr) |
str |
Original expression string |
CronScheduler
from cron_parser_py import CronParser, CronScheduler
expr = CronParser.parse("0 9 * * *")
CronScheduler.next_run(expr)
CronScheduler.next_runs(expr, count=10)
CronScheduler.previous_run(expr)
CronScheduler.is_due(expr, tolerance_seconds=30)
CronScheduler.time_until_next_run(expr) # → timedelta
CronValidator
from cron_parser_py import CronParser, CronValidator
expr = CronParser.parse("0 0 30 2 *")
errors = CronValidator.validate(expr, strict=True)
# ["The combination of month(s) and day(s) can never produce a valid date ..."]
CronValidator.assert_valid(expr, strict=True) # raises CronValidationError
warnings = CronValidator.get_warnings(expr)
CronDescriptor
from cron_parser_py import CronParser, CronDescriptor
expr = CronParser.parse("0 9 * * MON-FRI")
CronDescriptor.describe(expr) # "At 9:00 AM, Monday through Friday"
# Describe a single field
from cron_parser_py import FieldType
from cron_parser_py.parser import parse_field
field = parse_field("MON-FRI", FieldType.DAY_OF_WEEK)
CronDescriptor.describe_field(field) # "Monday through Friday"
Exceptions
from cron_parser_py import (
CronParseError, # base class
CronValidationError, # invalid expression structure
CronFieldError, # invalid value in a specific field
CronScheduleError, # cannot calculate run time
)
Examples
from datetime import datetime
import cron_parser_py as cron
# -- Descriptions --
cron.describe("* * * * *") # "Every minute"
cron.describe("*/5 * * * *") # "Every 5 minutes"
cron.describe("0 * * * *") # "Every hour"
cron.describe("0 */2 * * *") # "Every 2 hours"
cron.describe("0 9 * * *") # "At 9:00 AM"
cron.describe("30 14 * * *") # "At 2:30 PM"
cron.describe("0 9,17 * * *") # "At 9:00 AM and 5:00 PM"
cron.describe("0 9 * * 1-5") # "At 9:00 AM, Monday through Friday"
cron.describe("0 9 * * 1,3,5") # "At 9:00 AM, on Monday, Wednesday, and Friday"
cron.describe("0 0 1 * *") # "At midnight, on the 1st"
cron.describe("0 0 L * *") # "At midnight, on the last day of the month"
cron.describe("0 0 ? * 5#2") # "At midnight, on the second Friday of the month"
cron.describe("0 0 1 1 *") # "At midnight, on the 1st, in January"
cron.describe("@weekly") # "Weekly, at midnight on Sunday"
# -- Scheduling --
ref = datetime(2024, 6, 10, 8, 0) # Monday 08:00
nxt = cron.next_run("0 9 * * MON-FRI", ref)
# datetime(2024, 6, 10, 9, 0) — same day at 09:00
runs = cron.next_runs("*/30 8-18 * * 1-5", count=4, from_time=ref)
# Four 30-minute slots on weekdays between 08:00 and 18:00
prev = cron.previous_run("0 0 * * *", ref)
# datetime(2024, 6, 10, 0, 0) — midnight that day
td = cron.parse("0 9 * * *").next_run(ref) - ref
print(td) # 1:00:00 (1 hour)
License
MIT © Vladyslav Zaiets
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 cron_parser_py-1.0.0.tar.gz.
File metadata
- Download URL: cron_parser_py-1.0.0.tar.gz
- Upload date:
- Size: 17.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f6627618cb0588be2b0e7ad3b4739b3473bc54ae799a7b2fc2215c718e8b84ec
|
|
| MD5 |
25ea785cf8b0987081e7990656789866
|
|
| BLAKE2b-256 |
39741603da497dd7bc3cfedff7e98e70f1d515b30609eaac826526ab95ed9cb0
|
File details
Details for the file cron_parser_py-1.0.0-py3-none-any.whl.
File metadata
- Download URL: cron_parser_py-1.0.0-py3-none-any.whl
- Upload date:
- Size: 21.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
583443bca6cb2d38b2eed07e9c34da7bea55f44de50e9eb0f5e4d83eeb3e2121
|
|
| MD5 |
03e619b27ab6c4351f2b6a8c5cc6c16c
|
|
| BLAKE2b-256 |
2a79534f953ae81a0bc06a1b9d59e42d3b37de5f626e5665a8804e473186fe1c
|