cronkit.org
Cron expressions, explained and converted — in your browser

Cron tools › Reference

Cron cheat sheet

fields · special characters · macros · 14 dialects compared · workarounds

Everything you look up when writing a cron schedule, checked against each scheduler's own documentation or source. Click any expression in a table to load it into the parser below and see its next runs.

Runs

Try one

The five fields

#FieldValuesNamesExample
1Minute0-59—
2Hour0-23—
3Day of month1-31—
4Month1-12JAN-DEC
5Day of week0-7 (0 and 7 = Sunday)SUN-SAT

Names are the first three letters, case-insensitive. After the fifth field comes the command; in /etc/crontab and /etc/cron.d/ a user name comes first. Quartz and Spring put a seconds field (0-59) in front; Quartz allows a trailing year and AWS EventBridge requires one (1970-2199).

Special characters

CharMeansExampleSupported by
*every valueall dialects
,listall dialects
-range, inclusiveall dialects. Wrap-around ranges such as 22-2 or FRI-MON work in Quartz, node-cron and Celery; elsewhere write two ranges
/step: every n-th value of a rangeall dialects; AWS not in day of week. Steps restart each hour: */35 fires at :00 and :35. 20/15 (from 20) = 20, 35, 50 in GitHub Actions, Kubernetes and GitLab; in a Linux crontab write 20-59/15
?no specific valueQuartz and AWS (required in exactly one day field); Spring and Kubernetes read it as *; node-cron accepts it too
Llast: day of month L, L-3; in day of week 6L = last Friday (Quartz numbering)Quartz, AWS, Spring, node-cron, Cloudflare Workers, GitLab. Quartz: L alone in day of week = Saturday. AWS does not document L-n
Wweekday nearest a date: 15W; LW = last weekdayQuartz, AWS, Spring, node-cron, Cloudflare Workers. Quartz never crosses the month: 1W on a Saturday is Monday the 3rd. AWS does not document LW
#n-th weekday of the month: 2#1 = first Monday (Quartz numbering)Quartz (1-5), AWS (one # per expression), Spring, node-cron, Cloudflare Workers, GitLab
Hhash: a value derived from the job nameJenkins only: H, H/15, H(0-29), H(0-29)/10. Plain H in day of month stays within 1-28
~random value, picked when the crontab is loaded6~15cronie only — no tool can predict the run time

@ shorthands

MacroLinux (crontab(5))KubernetesSpringJenkins
@yearly, @annually0 0 1 1 *yes0 0 0 1 1 *H H H H *
@monthly0 0 1 * *yes0 0 0 1 * *H H H * *
@weekly0 0 * * 0yes0 0 0 * * 0H H * * H
@daily0 0 * * *yes0 0 0 * * *H H * * *
@midnightcronie and Debian: same as @dailyyes0 0 0 * * *H H(0-2) * * *
@hourly0 * * * *yes0 0 * * * *H * * * *
@rebootwhen the cron daemon starts — possibly before other system daemonsnonono

node-cron accepts the macros except @reboot; GitLab (fugit) adds @noon. GitHub Actions explicitly rejects all of them, Quartz has none, and AWS has no macros but offers rate(5 minutes) (singular unit for 1: rate(1 hour)). Jenkins' macros use H, so @daily is a different time for each job.

Dialects compared

DialectFieldsDay of weekBoth day fields setTime zoneMost often
Linux (Vixie, cronie)5 (+ user in /etc/crontab)0-7, 0 and 7 = SunOR — unless either field starts with *, then ANDsystem zone; CRON_TZ in cronie; Debian: none per user1 minute
Kubernetes CronJob50-6 (7 rejected)OR — unless either is a bare *controller's zone; .spec.timeZone (stable since 1.27)1 minute
GitHub Actions50-6not documentedUTC; timezone: key since March 20265 minutes
Google Cloud Scheduler50-6 or 7OR unless a field is *timeZone field, default UTC1 minute
GitLab (fugit)5 (+ optional seconds)numbers or namesOR; a trailing & forces ANDper schedulethe schedule worker (GitLab.com: every 5 min)
Quartz6-7 (sec … [year])1-7, 1 = Sunnot allowed: one must be ?set on the trigger1 second
AWS EventBridge6 (… year), in cron( )1-7, 1 = Sunnot allowed: one must be ?rules: UTC; Scheduler: IANA zone1 minute
Spring @Scheduled6 (sec first)0-7 or MON-SUNANDzone attribute1 second
Jenkins5, digits only0-7ANDTZ= on the first line1 minute
Azure Functions6 (sec first; 5 also)0-6ANDUTC; WEBSITE_TIME_ZONE1 second
Celery crontab()5 keyword arguments0-6, Sun = 0ANDUTC by default1 minute
node-cron5 or 6 (sec first)0-7ANDtimezone option1 second
Vercel5, no names0-6not allowed: one must be *always UTCHobby: once a day (±59 min); Pro: 1 minute
Cloudflare Workers51-7, 1 = Sunnot documentedUTCnot documented

The OR rule in practice: runs on the 1st and on every Monday. Starting a field with * flips Linux cron to AND, so is "Mondays on odd dates" — but Kubernetes only treats a bare * as unrestricted, so there is "odd dates or Mondays". Same string, different schedule.

Last day of the month in Linux cron

Linux cron has no L. Run on every day that can be the last one, and let the shell keep only the day whose tomorrow is the 1st:

0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = 01 ] && /usr/local/bin/month-end.sh

First Monday of the month in Linux cron

The tempting is wrong: with both day fields set, cron runs on the 1st to the 7th and on every Monday. Schedule the seven possible dates and test the weekday instead (date +%u prints 1 for Monday … 7 for Sunday):

0 9 1-7 * * [ "$(date +\%u)" = 1 ] && /usr/local/bin/report.sh

For the n-th Monday use days 8-14, 15-21 or 22-28. Quartz writes it as , AWS as cron(0 9 ? * 2#1 *), Spring as 0 0 9 * * 1#1 — note the different numbers for Monday. The text to cron tool writes these workarounds from a sentence.

Daylight saving time

SchedulerWhat happens when the clocks change
cronieChanges of less than three hours get special handling, but only for jobs at a specific time or with a granularity above one hour. Clocks forward: those jobs whose time was skipped run immediately. Clocks back: they do not run twice. More frequent jobs are scheduled normally.
Debian / Ubuntu cronThe same special handling, applied to jobs not written as @hourly and without * in the hour or minute field.
GitHub ActionsUTC by default, so no DST. With a timezone:, a 02:30 schedule on the day that hour is skipped runs at 03:00.
AWS EventBridgeRules run in UTC. EventBridge Scheduler with a time zone skips a time that does not exist and runs once in a repeated hour.
iCalendar RRULELocal times that do not exist "MUST be ignored".
Vercel, Cloudflare Workers, Google Cloud and Azure defaultsUTC, so the schedule never shifts — but its local time moves by an hour twice a year.
Kubernetes, Quartz, Spring, Jenkins, node-cron, CeleryNot in our verified notes. Look at the runs around the change dates in the next run calculator.

The safest schedule is one that does not care: avoid 01:00-03:00 local time for daily jobs, or run the scheduler in UTC. The crontab checker flags jobs inside the skipped hour.

How to read a cron expression

  1. Count the fields: five is Linux style, six with seconds first is Quartz or Spring, six ending in a year is AWS.
  2. Read the time fields left to right — minute, hour — then the day fields.
  3. If both day fields are set, check the dialect's rule in the table above: OR, AND, or not allowed.
  4. Check the weekday numbering before trusting any digit in the last field.
  5. Paste it into the parser at the top of this page to see the next runs in your time zone.

FAQ

Is Sunday 0 or 7?

Both, in Linux cron, Spring, node-cron, Jenkins and Google Cloud Scheduler. Kubernetes, Azure and Celery accept only 0. Quartz, AWS and Cloudflare Workers count 1 = Sunday to 7 = Saturday.

Can cron run every 30 seconds?

Not Linux cron — its smallest unit is the minute. Quartz, Spring, Azure Functions and node-cron have a seconds field: */30 * * * * * in Spring. On Linux, two crontab lines with one running sleep 30 first is the usual workaround.

Why did my job run on the wrong day?

Usually the day-of-month OR rule (0 0 1-7 * 1 runs every day of the first week and every Monday) or weekday numbering copied between Linux and Quartz or AWS, where 1-5 means Sunday to Thursday.

Can I put a comment at the end of a crontab line?

No. Cron does not allow comments on the same line as a command or an environment setting — put # comments on their own line.