Aide-mémoire et exemples pratiques sur les expressions Cron

What Is a Cron Expression?

A cron expression is a short schedule string that tells a scheduler when to start a recurring task. Standard Unix and Linux cron uses five time-and-date fields, in this fixed order: minute, hour, day of month, month, and day of week. A user crontab line places a command after those five fields, and the cron daemon runs that command whenever the fields match the current time.

Here is the most common example in production:

texte0 2 * * *

Plain English: run every day at 02:00 (2:00 AM) in the scheduler’s configured timezone.

Compatibility note: this guide starts with five-field Unix/Linux cron. Other schedulers may use a different field count, timezone setting, or special characters. Quartz expressions, for example, normally use six or seven fields, including seconds. Amazon EventBridge Scheduler also uses six fields, including a year.

Cron Syntax: The Five Fields

The five fields are positional. Reading them left to right is the fastest way to decode any expression.

texte┌──────────── minute (0–59)
│ ┌────────── hour (0–23)
│ │ ┌──────── day of month (1–31)
│ │ │ ┌────── month (1–12)
│ │ │ │ ┌──── day of week (platform-dependent; POSIX uses 0 for Sunday)
│ │ │ │ │
* * * * *
PositionFieldTypical valuesExampleMeaning
1Minute0–5930 * * * *At 30 minutes past every hour
2Hour0–230 6 * * *Daily at 06:00
3Day of month1–310 0 1 * *Midnight on the 1st
4Month1–120 0 1 7 *Midnight on 1 July
5Day of weekPOSIX 0–6 with 0 = Sunday0 12 * * 1Mondays at 12:00

Two crontab shapes matter, because getting them mixed up is a classic failure:

  • A user crontab line contains the five scheduling fields followed by the command to run.
  • A system crontab line (for example /etc/crontab or files in /etc/cron.d) contains the five scheduling fields, then a username, then the command.

If you paste a user-crontab line into a system crontab file, cron will try to read your command’s first word as a username. Always check your platform’s documentation before copying a schedule between files or between services.

Cron Special Characters

Four operators are standard across POSIX-style cron and the common Linux implementations derived from Vixie cron.

SymbolPurposeExampleMeaning
*Every valid value*/5 * * * *Every 5 minutes
,A list0 9,17 * * *At 09:00 and 17:00
-An inclusive range0 9-17 * * 1-5At the top of each hour from 09:00 through 17:00, Monday to Friday
/A step interval*/15 * * * *Every 15 minutes

POSIX itself defines the asterisk, the comma list, and the hyphen range. The step operator / comes from the Vixie cron extension, where following a range with /<number> skips through that range, and steps are also permitted after an asterisk.

A step interval follows the clock and calendar, not your task’s completion time. */5 * * * * fires at minute 0, 5, 10, and so on. It does not mean “five minutes after the previous run finishes.”

Platform-specific operators and macros

Symbols such as ?, L, W, et #, plus macros such as @reboot, @hourly, @daily, @weekly, @monthly, et @yearly, are implementation-specific. They exist in some schedulers and not others, and they behave differently between them. Vixie/cronie-style Linux cron documents the @-macros and named month and weekday values. L, W, et # are Quartz-style tokens, and Quartz uses ? in the day fields. Kubernetes CronJob supports the @-macros and treats ? as equivalent to *. Vercel Cron Jobs rejects name aliases such as MON ou JAN entirely. Use these only when your target scheduler’s own documentation lists them.

Cron Expression Cheat Sheet: Common Examples

Every expression below is standard five-field Unix/Linux syntax. Times are shown in 24-hour format and are interpreted in the scheduler’s configured timezone.

Every Minute and Sub-Hourly Schedules

ExpressionPlain English
* * * * *Every minute of every day
*/5 * * * *Every 5 minutes (minute 0, 5, 10, …)
*/10 * * * *Every 10 minutes
*/15 * * * *Every 15 minutes (:00, :15, :30, :45)
*/30 * * * *Every 30 minutes (:00 and :30)

Sub-hourly schedules are where reliability problems appear first. Some managed platforms refuse very frequent schedules: GitHub Actions sets the shortest supported interval at once every 5 minutes.

Hourly Schedules

ExpressionPlain English
0 * * * *At the top of every hour
15 * * * *At 15 minutes past every hour
0 */2 * * *Every 2 hours, on the hour (00:00, 02:00, 04:00, …)
5,35 * * * *Twice an hour, at :05 and :35

Staggering minutes with a list like 5,35 is useful in practice. If dozens of jobs all fire at minute 0, they compete for CPU, database connections, and API rate limits at exactly the same moment.

Daily Schedules

ExpressionPlain English
0 0 * * *Every day at midnight (00:00)
0 2 * * *Every day at 02:00 (2:00 AM)
30 6 * * *Every day at 06:30 (6:30 AM)
45 23 * * *Every day at 23:45 (11:45 PM)

Weekday and Weekly Schedules

ExpressionPlain English
0 9 * * 1-5At 09:00, Monday through Friday
30 8 * * 1-5At 08:30, Monday through Friday
0 0 * * 0At midnight on Sunday
0 10 * * 0,6At 10:00 on Sunday and Saturday

Day-of-week numbering is platform dependent. POSIX defines 0–6 with 0 as Sunday. Many Linux cron implementations accept 0–7, where both 0 and 7 mean Sunday, and also accept names. Quartz uses 1–7 for its day-of-week field instead, and AWS EventBridge Scheduler also uses 1–7 or SUN-SAT. Confirm the numbering in your scheduler’s documentation before you trust a weekend or weekday schedule.

Monthly and Yearly Schedules

ExpressionPlain English
0 0 1 * *Midnight on the 1st of every month
30 2 1 * *02:30 on the 1st of every month
0 0 1 1 *Midnight on 1 January, once a year
0 0 1 1,4,7,10 *Midnight on the 1st of January, April, July, and October

“Last day of the month” is not portable in basic five-field cron. There is no standard operator for it, so do not represent it with a generic expression. Quartz provides an L token in its own dialect, and EventBridge Scheduler lists L for its day-of-month and day-of-week fields, but neither belongs in a Linux crontab. On Linux, handle end-of-month logic inside your script, for example by running daily and exiting unless tomorrow is the 1st.

How to Read a Cron Expression

*/5 * * * *

texte*/5 * * * *
FieldValueReading
Minute*/5Every 5th minute, starting at 0
Hour*Every hour
Day of month*Every day
Month*Chaque mois
Day of week*Every weekday

Natural language: every 5 minutes, all day, every day. Timezone caveat: the minute grid is unaffected by timezone, but the log timestamps and any date-based logic inside your script are not.

0 9 * * 1-5

texte0 9 * * 1-5
FieldValueReading
Minute0On the hour
Hour909:00
Day of month*Any date
Month*Any month
Day of week1-5Monday through Friday

Natural language: at 09:00 (9:00 AM) on weekdays. Timezone caveat: 09:00 in which zone? On a Linux server this is usually server-local time, so the same expression can fire at a different wall-clock hour for your users than you expect.

30 2 1 * *

texte30 2 1 * *
FieldValueReading
Minute30At 30 past
Hour202:00 hour
Day of month1The 1st
Month*Chaque mois
Day of week*Not restricted

Natural language: at 02:30 (2:30 AM) on the first day of every month. Timezone caveat: monthly billing and reporting jobs scheduled near midnight or during a daylight-saving transition are the most likely to land on the wrong calendar day.

Day of Month vs. Day of Week

Both day fields exist because people describe schedules in two different ways: by date (“the 15th”) and by weekday (“every Friday”). Cron kept both, and the interaction between them is a genuine production risk.

In POSIX-style cron and common Vixie/Cronie-derived Linux implementations, when both day-of-month and day-of-week are restricted rather than *, a job can run when either field matches. Other schedulers may use different semantics or restrict that combination. The Linux manual page states it directly: commands run when the minute, hour, and month fields match et at least one of the two day fields matches. POSIX describes the same either/or logic when both day fields are specified as elements or lists.

Look at this expression:

texte0 0 15 * 5

In the applicable Unix/Linux behaviour, this may run at midnight on every 15th of the month et at midnight on every Friday. It does not necessarily mean “only on Fridays that happen to be the 15th.” In a typical month that is roughly five or six runs, not one.

Other platforms diverge sharply here. Vercel Cron Jobs does not allow both day fields to be set at once: when one has a value, the other must be *. AWS EventBridge Scheduler requires a ? in one day field when the other is specified. Quartz uses ? for the same purpose.

Safer recommendations:

  • Utiliser * in one day field unless you have verified the behaviour you need on your platform.
  • Use separate jobs, or application logic inside the task, for complex calendar rules such as “the third Friday” or “the last business day.”
  • Validate the expression against the exact scheduler and version you will deploy to, not against a general cron reference.

Cron Timezones and Daylight Saving Time

A cron expression does not carry a universal timezone. The same five fields can mean three different things depending on where they run:

  • Server-local time. A Linux cron daemon evaluates schedules against the host’s configured time. Some Linux cron implementations also support a CRON_TZ variable that sets a timezone for a specific crontab, with log timestamps still taken from the daemon’s local zone. Treat CRON_TZ as implementation-specific.
  • A platform default such as UTC. GitHub Actions runs scheduled workflows in UTC by default. Vercel Cron Jobs always uses UTC and offers no per-job timezone field.
  • An explicit IANA timezone setting. Kubernetes CronJob uses .spec.timeZone. GitHub Actions now accepts an optional timezone value alongside a cron entry. EventBridge Scheduler can evaluate cron schedules in UTC or in a timezone you specify. Spring’s @Scheduled has a zone attribute and otherwise uses the server’s default zone.

Daylight saving time creates two distinct failure modes, and the handling depends on the scheduler. Classic Linux cron documentation is blunt about it: non-existent local times during a spring-forward transition never match, so those jobs simply do not run, and times that occur twice during a fall-back transition cause matching jobs to run twice. GitHub Actions takes a different approach for timezone-aware schedules and advances a skipped time to the next valid time, so a 02:30 schedule moves to 03:00.

Practical guidance for sensitive work:

  • For billing, reporting, backups, and compliance jobs, prefer UTC or a fixed offset zone, then convert for display. UTC has no DST transitions.
  • For customer-facing messages that must land at a local hour, use a platform that supports an explicit IANA timezone, and accept that the UTC instant will shift twice a year.
  • Avoid scheduling anything important between 01:00 and 03:00 local time in DST-observing zones. That window is where jobs get skipped or doubled.
  • Always read a next-run preview before deploying. Previews expose off-by-one-hour and wrong-day errors that an expression alone hides.

Kubernetes-specific example (not generic crontab syntax):

texteapiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-report
spec:
  schedule: "0 2 * * *"
  timeZone: "Europe/London"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: report
              image: your-registry/report:1.0
          restartPolicy: OnFailure

Kubernetes rejects TZ ou CRON_TZ inside the schedule string with a validation error, so the timezone must go in the timeZone field.

GitHub Actions-specific example (not generic crontab syntax):

texteon:
  schedule:
    - cron: '30 5 * * 1-5'
      timezone: "America/New_York"

This runs at 05:30 New York time, Monday through Friday.

Vercel compatibility note: Vercel Cron Jobs uses five numeric fields and always interprets them as UTC, with no timezone option. If your team wants 09:00 in London, you must calculate the UTC hour yourself and revisit it when British Summer Time starts and ends.

Cron Formats by Platform

Platform/contextTypical field formatTimezone approachImportant note
Unix/Linux user crontabFive fields, then the commandHost-local time; some implementations support CRON_TZ per tableDay-of-week commonly accepts 0–7 with 0 or 7 as Sunday, plus names
Unix/Linux system crontabFive fields, then a username, then the commandSame as the host cron daemonThe extra username field is the difference; omitting it breaks the line
Kubernetes CronJobFive fields in .spec.schedule, with Vixie step values and @-macros.spec.timeZone with an IANA name; otherwise the controller’s local zone? behaves like *; TZ/CRON_TZ in the schedule are rejected
Vercel Cron JobsFive numeric fieldsAlways UTC, no per-job optionNon MON/JAN aliases, and day-of-month and day-of-week cannot both be set
GitHub Actions schedulesFive POSIX fields under on.scheduleUTC by default; optional IANA timezone valueShortest interval is every 5 minutes; runs can be delayed under high load
Quartz SchedulerSix or seven fields including seconds and optional yearConfigured in the scheduler/trigger, not in the expression?, L, W, et # are Quartz tokens; day-of-week is 1–7
Other cloud schedulers and librariesVaries: EventBridge Scheduler uses six fields with a year; Spring @Scheduled uses six fields starting with secondsEventBridge supports UTC or a chosen zone; Spring uses a zone attributeCheck the platform’s own reference; field counts and day-field rules differ

Anything not listed in your platform’s own documentation should be treated as unsupported until you have tested it.

Common Cron Mistakes and Fixes

ProblèmeCause probableSafer fix
Scheduler rejects the expression outrightA six-field Quartz or Spring expression pasted into a five-field schedulerCount the fields first; rewrite for the target dialect instead of trimming blindly
Expression works in one service, fails in anotherAssuming cron syntax is universalConfirm field count, allowed values, and special characters in the target documentation
Weekend job never firesAssuming both 0 et 7 always mean SundayPOSIX uses 0 for Sunday; many Linux implementations also accept 7, but support varies, so follow your scheduler’s docs
Job runs at the wrong hourIgnoring the scheduler timezone; UTC-only platforms are commonSet an explicit timezone where supported, or convert to UTC deliberately
Job skipped or duplicated twice a yearDaylight saving transitions; classic cron never matches skipped times and matches doubled times twiceUse UTC for critical work, or a scheduler that documents its DST behaviour
Job runs far more often than intendedBoth day fields restricted, so either can matchLeave one day field as *, or split into separate jobs
Runs bunch up unexpectedlyTreating */5 as a delay after the previous run completesSteps follow the clock; use a fixed-delay scheduler if you need gap-based timing
Overlapping executions corrupt dataRuntime exceeds the schedule intervalWrap the command in a lock, for example flock -n /tmp/job.lock /path/to/job.sh; in Kubernetes set concurrencyPolicy: Forbid
One-time task fires repeatedlyUsing a recurring cron schedule for a single eventUse a one-shot mechanism such as a scheduled at-time invocation or a queued job
Silent failures nobody noticesNo logs, alerts, retries, or idempotencyRedirect standard output and standard error to a log, add alerting, and design tasks to be safely repeatable
Credentials leak into process lists and historySecrets typed directly into the crontab command lineRead secrets from environment variables or a secrets manager inside the script
Untested schedule breaks productionDeploying straight to the real workloadTest with a harmless command first, for example * * * * * /bin/date >> /tmp/cron-test.log 2>&1, then check the log

Two reliability points deserve emphasis. Cron does not guarantee exact execution times: GitHub Actions warns that scheduled workflows can be delayed during periods of high load and may be dropped from the queue. Kubernetes states that a CronJob creates a Job approximately once per scheduled time, that two Jobs or no Job may occasionally be created, and that your Jobs should therefore be idempotent. Kubernetes also stops starting Jobs after more than 100 missed schedules and logs an error instead. Design for delays, duplicates, and misses rather than assuming perfect timing.

Cron Expression Generator

Hippotool is building an interactive cron expression generator to sit alongside this cheat sheet. When it launches, you will be able to build or paste a schedule, select the target platform, read a plain-English explanation, and preview the next scheduled runs. In the meantime have a look at our frontend playground for live HTML/CSS, Javascript preview.

The functions planned for the tool map directly to the mistakes above:

  • Default Unix/Linux five-field mode, so the safest dialect is the starting point
  • A platform and dialect selector covering Linux crontab, Kubernetes CronJob, Vercel, GitHub Actions, and Quartz
  • A generator/builder for people who prefer dropdowns over raw syntax
  • A parser and plain-English translator for expressions you inherited from someone else
  • The next 10 run times, so you can sanity-check the schedule visually
  • An IANA timezone selector, with UTC as an explicit option
  • A copy button for clean copy-paste schedules
  • Validation errors that name the offending field
  • A field-count mismatch warning when a six-field expression meets a five-field target
  • A day-of-month/day-of-week warning that explains the either/or matching behaviour
  • Platform-specific warnings, such as UTC-only scheduling or unsupported name aliases
  • No silent conversion between Unix/Linux and Quartz formats, because a quiet rewrite hides real semantic differences

Until it is live, validate expressions against your scheduler’s own tooling and documentation, and confirm behaviour with a harmless test job.

Foire aux questions

What is a cron expression?

A cron expression is a schedule string that tells a scheduler when to start a recurring task. In standard Unix and Linux cron it has five fields, in order: minute, hour, day of month, month, and day of week. In a user crontab, the command to run follows those five fields. Different schedulers use different field counts and rules.

What does * * * * * mean?

texte* * * * *

Every field is unrestricted, so the schedule matches every minute of every hour, every day of every month. In practice the task starts once per minute, because Linux cron examines its entries every minute. Use this only for short, cheap, overlap-safe work. Some platforms reject once-per-minute schedules; GitHub Actions allows no shorter than every 5 minutes.

How do I run a cron job every 5 minutes?

texte*/5 * * * *

Le / step operator in the minute field selects minute 0, 5, 10, and so on through 55. This is clock-based, not gap-based: if a run takes seven minutes, the next run still starts on the five-minute grid and can overlap. Add a lock such as flock if overlap would cause problems.

How do I run a cron job every hour?

texte0 * * * *

That fires at the top of every hour. To spread load away from minute 0, pick another minute, such as 17 * * * * for 17 minutes past each hour. For a multi-hour gap, use a step in the hour field: 0 */4 * * * runs at 00:00, 04:00, 08:00, 12:00, 16:00, and 20:00 in the scheduler’s timezone.

How do I schedule a cron job every day at a specific time?

Put the exact minute and hour in the first two fields and leave the rest as *. For example, 30 6 * * * runs daily at 06:30 (6:30 AM), and 45 23 * * * runs daily at 23:45 (11:45 PM). The hour field uses 0–23. Confirm which timezone the scheduler applies before you rely on the wall-clock time.

How do I schedule a cron job on weekdays?

texte0 9 * * 1-5

The range 1-5 in the day-of-week field covers Monday through Friday, giving a 09:00 weekday run. POSIX numbers the field 0–6 with 0 as Sunday, and many Linux implementations also accept names and the value 7 for Sunday. Quartz numbers day-of-week 1–7 instead, so the same digits mean different days there.

What is the difference between five-field and six-field cron?

Five-field cron is the standard Unix/Linux format: minute, hour, day of month, month, day of week. Six-field dialects add another unit. Quartz puts seconds first and allows an optional seventh year field. Spring’s @Scheduled also starts with seconds. AWS EventBridge Scheduler uses six fields where the extra one is a year. Field counts are not interchangeable.

Why is my cron job running at the wrong time?

The usual cause is timezone. The expression carries no zone of its own, so it may be evaluated in server-local time, a platform default such as UTC, or an explicit configured zone. Daylight saving transitions add an hour of drift or a skipped run. Platform delays are a second cause: scheduled runs can be postponed under load.

How do cron timezones work?

The scheduler decides, not the expression. Linux cron uses the host’s time and some implementations honour a CRON_TZ variable per crontab. Kubernetes reads .spec.timeZone. GitHub Actions defaults to UTC with an optional timezone value. Vercel is always UTC. Set the zone explicitly where you can, and preview next run times.

Can I use cron syntax in Kubernetes?

Yes, with caveats. A Kubernetes CronJob takes a five-field schedule in .spec.schedule, supports Vixie step values, accepts macros such as @monthly, and treats ? comme *. The timezone belongs in .spec.timeZone, and putting TZ ou CRON_TZ in the schedule string causes a validation error. Design Jobs to be idempotent, since duplicates are possible.

Can I use the same cron expression in Vercel and Linux?

Sometimes, but do not assume it. Vercel uses five numeric fields, rejects aliases such as MON et JAN, requires * in one day field when the other is set, and always interprets the schedule as UTC. A Linux crontab line using names, both day fields, or server-local time will not transfer cleanly. Recheck the hour after any UTC conversion.

What is a Quartz cron expression?

Quartz uses an extended dialect of six or seven whitespace-separated fields: seconds, minutes, hours, day of month, month, day of week, and an optional year. It defines its own tokens, including ? for “no specific value,” plus L, W, et # in the day fields, and numbers day-of-week 1–7. Quartz expressions cannot be pasted into a Unix/Linux crontab.

How do I validate a cron expression before using it?

Work in three steps. First, count the fields and confirm they match your scheduler’s documented format. Second, generate a next-run preview and check the dates and hours against your intent, including the timezone. Third, deploy the schedule with a harmless command that only writes a timestamp to a log, confirm the log entries, then swap in the real command.

Final Takeaway

Identify the scheduler and its dialect, write the correct field count, then confirm which timezone the schedule will actually use. Preview the next run times and deploy once with a harmless command before you attach anything important to the schedule.