Cron Expression Parser & Crontab Builder

Explain cron expressions or build a crontab

Explain cron expressions or build a crontab

Fill with an example

Description

Enter a cron expression above to see its description and upcoming run times.

Field breakdown

Next run times (your local time)

    About Cron Expression Parser & Crontab Builder

    This tool reads a standard five-field Unix cron line (minute hour day-of-month month day-of-week), explains it in plain words, and finds the next run times by actually stepping forward minute by minute. The Builder tab works the other way round: pick a frequency, time and weekdays, and it writes the expression and checks it with the same rules.

    Cron lines are short, and most mistakes in them are not syntax errors. They are misreadings: listing both a day of month and a weekday gives you OR, not AND; the same line fires at different wall-clock times depending on the server's time zone; and Quartz or Spring expressions carry an extra seconds field. The sections below walk through those traps with concrete schedules.

    Day-of-month plus day-of-week means OR

    It is natural to read 0 9 1 * 1 as "9:00 on the 1st, but only if it is a Monday". POSIX says otherwise. When both the day-of-month and day-of-week fields are restricted (neither is *), a day matching either one fires the job. So that line runs at 9:00 on the 1st of every month and also at 9:00 every Monday. If one of the two fields is *, it drops out and the other behaves as you expect.

    The next-run calculation here follows the same rule: it remembers whether each of the two fields was literally * and switches to OR only when both are restricted. If you really need an intersection such as "the first Monday of the month", standard cron cannot express it. The usual workaround is 0 9 1-7 * * with a weekday check inside the script, since exactly one of days 1-7 is a Monday.

    Time zones: the same line, different hours

    A cron expression carries no time zone. Classic cron on Linux interprets it in the machine's local time, and this tool shows next runs in your browser's local zone. Cloud VMs and containers often default to UTC, so a job written as 0 9 * * * by someone in New York will run at 9:00 UTC, which is 5:00 or 4:00 in the morning locally depending on daylight saving.

    GitHub Actions schedules also run in UTC by default. GitHub's documentation now describes an optional timezone key that takes an IANA name such as America/New_York, but most existing workflows were written in UTC, so read them that way unless the key is present. The same page notes that the shortest interval is five minutes, that runs can be delayed at busy times such as the top of every hour (and queued jobs may even be dropped under heavy load), and that scheduled workflows in public repositories are disabled after 60 days without repository activity. Picking an odd minute like 7 * * * * sidesteps the top-of-hour rush.

    Daylight saving: skipped and repeated hours

    In zones with DST, one night a year skips an hour and another repeats one. On the spring-forward date, 2:30 simply does not exist; on the fall-back date, 1:30 happens twice. Schedulers disagree about what to do. Some cron implementations run a skipped job right after the jump and avoid running a repeated one twice; others just skip it. GitHub documents that, when a DST-observing timezone is set, jobs in a skipped hour move to the next valid time (2:30 becomes 3:00).

    The dependable fixes are dull ones: avoid scheduling between roughly 1:00 and 3:00 local time, or run servers on UTC and write expressions in UTC. Because this tool lists runs in your browser's zone, stepping across a DST change date shows the effect directly.

    Five fields vs six or seven: Quartz and Spring

    Unix cron starts at minutes and has five fields. Quartz, and Spring's @Scheduled which follows it, put seconds in front for six fields, with an optional seventh for the year. The Quartz expression 0 0 9 * * ? therefore means the same as Unix 0 9 * * *.

    Other differences bite too. Quartz does not support giving values to both day-of-month and day-of-week; one of them must be ?. Its weekday numbers run 1 = Sunday to 7 = Saturday, while Unix uses 0 = Sunday (and accepts 7 as Sunday). This tool reads only five fields, but when you paste six or seven it says it looks like Quartz/Spring and, if the meaning carries over exactly, offers a button to convert it to five fields. It won't convert when the seconds field isn't 0, when there's a specific year, or when Quartz-only syntax such as L, W or # appears, since five-field cron can't express those. A six-field line with numeric weekdays is also left alone, because Quartz counts 1 = Sunday while Spring counts 0 = Sunday like Unix; use names like MON-FRI, or drop the seconds and turn ? into * yourself, shifting numeric weekdays down by one if it's Quartz.

    Building expressions in the Builder tab

    The Builder fills in only the fields your chosen frequency needs and leaves the rest as *. Intervals come out as */N, and that deserves a second look: */N means every Nth value counted from the field's start (0 for minutes), not every N minutes from when you saved the file. */7 fires at minutes 0, 7, … 56 and then 0 again, so the gap across the hour is four minutes. Divisors of 60 (5, 10, 15, 20, 30) behave the way people expect.

    Paste an existing crontab line into the expression box and the Builder decodes it back into its controls, which is handy for editing someone else's schedule. Selecting both weekdays and month days in the Builder still produces the OR behaviour described above.

    Worked examples

    The OR rule in action

    Input
    0 9 1 * 1 (from Tuesday 2026-09-22)
    Output
    Mon 9/28 09:00, Thu 10/1 09:00, Mon 10/5 09:00, Mon 10/12 09:00, Mon 10/19 09:00

    October 1 is a Thursday and the job still runs, because the 1st OR any Monday qualifies.

    GitHub Actions at 9:00 New York time

    Input
    cron: '0 13 * * 1-5' (no timezone key)
    Output
    13:00 UTC Mon–Fri = 09:00 EDT in summer, 08:00 EST in winter

    A UTC schedule does not follow DST, so the local time shifts by an hour twice a year. Setting timezone: "America/New_York" with 0 9 * * 1-5 keeps it at 9:00 local.

    A date that never comes

    Input
    0 0 30 2 *
    Output
    No upcoming runs

    February 30 does not exist. The tool searches up to four years ahead minute by minute and shows an empty list if nothing matches. A day-31 schedule quietly skips 30-day months.

    Translating a Quartz expression

    Input
    Quartz: 0 30 8 ? * MON-FRI
    Output
    Unix: 30 8 * * 1-5

    Remove the leading seconds, replace ? with *. Named weekdays match in both formats; numeric ones need shifting because Quartz counts Sunday as 1.

    How to use it

    1. Paste a cron line into the Parser tab, or type a macro such as @daily.
    2. Read the plain-language description and the next runs in your local time.
    3. To write a new schedule, use the Builder tab and copy the generated line.

    Frequently asked questions

    Why does 0 9 1 * 1 also run every Monday?

    When both day-of-month and day-of-week are restricted, POSIX cron fires on a day matching either one. For an intersection, leave one field as * and check the other condition in your script.

    My GitHub Actions schedule runs hours off.

    The schedule's cron is evaluated in UTC unless a timezone key is given. Convert your local time to UTC, or add a timezone with an IANA name.

    Can cron run every few seconds?

    Standard cron's smallest unit is one minute. Seconds exist only in six-field formats such as Quartz and Spring; this tool reads five fields (a six- or seven-field line whose seconds are 0 can be converted).

    Is 7 a valid weekday?

    Most Unix crons treat 7 as Sunday, and so does this tool. The POSIX range is 0-6, though, so 0 is the portable choice.

    Why is my */7 schedule uneven?

    */N lists values from the field's start in steps of N and restarts each hour, so unless N divides 60 the last gap of the hour is shorter.

    Sources

    Last reviewed:

    Privacy and how data is handled