# Cron expression parser and explainer

> Translate a five-field cron expression or crontab line into plain English and list its next run times after any start date and time, in UTC.

Versión interactiva: https://www.calcopenly.com/es/programming/cron-expression-parser
Tema: Calculadoras de programación y tecnología

A cron expression has five fields: minute (0–59), hour (0–23), day of month (1–31), month (1–12 or JAN–DEC) and day of week (0–7 or SUN–SAT, where 0 and 7 both mean Sunday). Each field takes a single value, a comma-separated list, a range with a hyphen or a step with a slash. The parser expands every field into its set of values, then scans forward day by day for the minutes that match all five.

The default, */15 9-17 * * MON-FRI, runs every 15 minutes from 09:00 to 17:45 on weekdays, which is 36 runs on each matching day. Started at midnight on Thursday 15 January 2026, its first run is 09:00 that morning.

When day of month and day of week are both restricted, cron runs on days that match either one, as crontab(5) specifies. Times here are UTC; a cron daemon uses its server's time zone, or CRON_TZ in cronie.

## Datos

- **Expresión cron**: minute hour day-of-month month day-of-week, e.g. 30 2 * * 1 — or @hourly, @daily, @weekly, @monthly, @yearly.
- **Start date (UTC)**
- **Start time (UTC)**: Runs are listed strictly after this moment.
- **Runs to list**

## Resultados

- Next run — resultado principal
- In plain English
- Upcoming runs
- Time until the next run
- Runs on each matching day

## Fórmula

$$
\begin{aligned} \text{run} &\iff m \in M \land h \in H \\ &\qquad \land\ \text{month} \in Mo \land \text{day} \\ \text{day} &= \begin{cases} \text{DOM} \lor \text{DOW} & \text{both} \ne * \\ \text{DOM} \land \text{DOW} & \text{otherwise} \end{cases} \end{aligned}
$$

## Ejemplos resueltos

### Every 15 minutes in office hours

- Expresión cron: */15 9-17 * * MON-FRI
- Start date (UTC): 2026-01-15
- Start time (UTC): 00:00
- **Next run: Thu 2026-01-15 09:00 UTC**
- **Upcoming runs: Thu 2026-01-15 09:00 UTC
Thu 2026-01-15 09:15 UTC
Thu 2026-01-15 09:30 UTC
Thu 2026-01-15 09:45 UTC
Thu 2026-01-15 10:00 UTC
Thu 2026-01-15 10:15 UTC
Thu 2026-01-15 10:30 UTC
Thu 2026-01-15 10:45 UTC
Thu 2026-01-15 11:00 UTC
Thu 2026-01-15 11:15 UTC**
- **Runs on each matching day: 36**
- **Time until the next run: 9 h**
- Fuente de comprobación: Brute-force Python 3.8 datetime scan minute by minute with an independent field parser; 4 minutes × 9 hours = 36 runs a day; 09:00 − 00:00 = 32400 s

### Daily at 09:00, starting exactly at 09:00 (edge)

- Expresión cron: 0 9 * * *
- Start date (UTC): 2026-01-15
- Start time (UTC): 09:00
- Runs to list: 3
- **Next run: Fri 2026-01-16 09:00 UTC**
- **In plain English: At 09:00, every day**
- **Upcoming runs: Fri 2026-01-16 09:00 UTC
Sat 2026-01-17 09:00 UTC
Sun 2026-01-18 09:00 UTC**
- Fuente de comprobación: crontab(5): runs are strictly after the start; confirmed by the Python brute-force scan

### Leap day only

- Expresión cron: 0 0 29 2 *
- Start date (UTC): 2026-01-15
- Start time (UTC): 00:00
- Runs to list: 3
- **Next run: Tue 2028-02-29 00:00 UTC**
- **Upcoming runs: Tue 2028-02-29 00:00 UTC
Sun 2032-02-29 00:00 UTC
Fri 2036-02-29 00:00 UTC**
- Fuente de comprobación: Python 3.8 calendar.isleap and datetime weekday, via the brute-force scan

### Day 1 or Monday (both day fields restricted)

- Expresión cron: 0 12 1 * MON
- Start date (UTC): 2026-01-15
- Start time (UTC): 00:00
- Runs to list: 5
- **Upcoming runs: Mon 2026-01-19 12:00 UTC
Mon 2026-01-26 12:00 UTC
Sun 2026-02-01 12:00 UTC
Mon 2026-02-02 12:00 UTC
Mon 2026-02-09 12:00 UTC**
- Fuente de comprobación: crontab(5) OR rule for day-of-month and day-of-week, checked by the Python brute-force scan

### Star-step day of month uses AND (Vixie quirk)

- Expresión cron: 0 0 */2 * FRI
- Start date (UTC): 2026-01-15
- Start time (UTC): 00:00
- Runs to list: 3
- **Upcoming runs: Fri 2026-01-23 00:00 UTC
Fri 2026-02-13 00:00 UTC
Fri 2026-02-27 00:00 UTC**
- Fuente de comprobación: Vixie cron entry.c sets DOM_STAR when the field starts with *, so both fields must match; Python brute-force scan

### @weekly macro

- Expresión cron: @weekly
- Start date (UTC): 2026-01-15
- Start time (UTC): 00:00
- Runs to list: 2
- **Next run: Sun 2026-01-18 00:00 UTC**
- **Upcoming runs: Sun 2026-01-18 00:00 UTC
Sun 2026-01-25 00:00 UTC**
- Fuente de comprobación: crontab(5): @weekly = 0 0 * * 0; Python brute-force scan

## Preguntas

### What does */5 mean in a cron expression?

*/5 means every 5th value of the field, counted from the field's first value. In the minute field it fires at minutes 0, 5, 10 … 55, which is 12 times an hour. A step can follow a range too: 10-30/10 gives minutes 10, 20 and 30. Steps restart each hour, so */7 runs at minute 56 and then again at minute 0.

### How do I run a cron job every day at midnight?

Write 0 0 * * *, which means minute 0 of hour 0 on every day, or use the @daily macro, which cronie and Vixie cron expand to the same five fields. For 2:30 a.m. every day write 30 2 * * *, and for 09:00 on weekdays write 0 9 * * 1-5. The hour is read in the server's time zone unless the crontab sets CRON_TZ.

### How do day of month and day of week combine in cron?

If both fields are restricted, cron runs when either one matches, so 0 12 1 * MON fires at noon on the 1st of every month and on every Monday. In Vixie cron and cronie, a day field that starts with * switches this to both, which is why 0 0 */2 * FRI runs only on Fridays that fall on odd dates such as the 23rd.

### Why does my cron expression have 6 or 7 fields?

Standard cron uses 5 fields. Quartz and Spring schedulers put a seconds field in front, making 6, and Quartz accepts an optional year as a 7th, so an expression like 0 0/15 * * * ? belongs to those tools rather than crontab; the ? placeholder is Quartz syntax. This parser reads the 5-field crontab format plus the @hourly, @daily, @weekly, @monthly and @yearly macros.

### Can cron run a job every 30 seconds?

Not directly: the smallest unit in a crontab is 1 minute, because the first field is the minute. The usual workaround is two entries, * * * * * job and * * * * * sleep 30; job, which start the job at 0 and 30 seconds past each minute. systemd timers accept OnCalendar schedules down to the second if you need finer control.

### ¿Qué precisión tiene «Cron expression parser and explainer»?

La precisión depende de tus datos y de los supuestos del método. El cálculo decimal usa 50 cifras significativas, pero las estimaciones, los métodos numéricos y los datos de origen pueden ser menos precisos; el redondeo mostrado no elimina esos límites. Ejemplos resueltos comprobados con fuentes independientes: 7. Por ejemplo, «Every 15 minutes in office hours» se comprueba con Brute-force Python 3.8 datetime scan minute by minute with an independent field parser; 4 minutes × 9 hours = 36 runs a day; 09:00 − 00:00 = 32400 s.

### ¿De dónde procede el método?

POSIX.1-2017 (IEEE Std 1003.1) — crontab utility, input file format; crontab(5) — cronie / Vixie cron: ranges, steps, names, @ macros and the day-of-month / day-of-week rule.

## Fuentes

- [POSIX.1-2017 (IEEE Std 1003.1) — crontab utility, input file format](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html)
- [crontab(5) — cronie / Vixie cron: ranges, steps, names, @ macros and the day-of-month / day-of-week rule](https://man7.org/linux/man-pages/man5/crontab.5.html)
