Cron once a year: 0 0 1 1 * with @yearly and @annually
0 0 1 1 * runs once a year at midnight on 1 January. Both @yearly and @annually expand to exactly this expression.
At a glance
- Expression
- 0 0 1 1 *
- Fires
- Once a year.
- Restricted fields
- Minute, hour, day of month and month all pinned. Only day of week is open.
- Equivalent macro
- @yearly and @annually both expand to 0 0 1 1 *.
- Fields pinned
- Four of the five. Only the day of week field is left open.
- Any date works
- 0 0 15 6 * is 15 June every year. The macro is just the 1 January case.
In detail
Pinning both the day of month and the month is what makes a schedule annual: the date matches on exactly one day a year, and the day of week field stays open so it does not matter which weekday that is. 0 0 1 1 * is the 1 January case, and both @yearly and @annually are shorthand for it.
There is nothing special about January in the syntax. 0 0 15 6 * runs every 15 June and 30 4 30 11 * runs at 04:30 on 30 November, so any valid day and month pair gives an annual schedule. The one caveat is that a February date above 28 exists only in leap years, which turns a yearly job into a once every four years job.
Once a year is a schedule where cron is arguably the wrong mechanism, because a crontab entry that runs annually will not be tested between runs and may not even survive the machine it lives on. If the job matters, the thing to monitor is not whether cron fired but whether the result exists, checked far more often than once a year.
The other thing to check is the day of week field. Leaving it as an asterisk is essential here: restricting it would trigger the OR rule and turn a once a year job into a weekly one, since the day of month and month restrictions would then be satisfied independently of the weekday match.
Examples
0 0 1 1 *@yearly /opt/app/bin/annual-archive.sh >> /var/log/archive.log 2>&1@annually is a synonym and expands to the same five fields.
0 2 15 6 * /opt/app/bin/annual-audit.sh02:00 on 15 June every year.
Things that catch people out
- 0 0 1 1 1 is not an annual Monday job. Restricting the day of week alongside the date makes cron fire on 1 January and on every Monday.
- An annual job on 1 January runs at a time when nobody is available. Pick a date in a working week if a human might need to respond.
- @yearly and @annually are the same schedule. Having both in one crontab means the job runs twice.
Try it: Cron Expression Parser
Paste any five or six field expression to get a plain English description, a per field breakdown and the next run times in your local time.
Cron Expression Parser
LOCAL · Browser-OnlyParse cron expressions and see the next scheduled run times
Supports 5-field (minute hour day month weekday), 6-field (with seconds), named values (JAN, MON), and @macros (@daily, @hourly, ...)
Use the dropdowns below to build your cron expression visually, or type a custom value in each field.
Human-Readable Description
Every 5 minutes
Field Breakdown
| Field | Allowed | Value | Meaning |
|---|---|---|---|
| Minute | 0-59 | */5 | every 5 minute(s) |
| Hour | 0-23 | * | every hour |
| Day of Month | 1-31 | * | every day of month |
| Month | 1-12 | * | every month |
| Day of Week | 0-7 | * | every day of week |
Related cron expressions
All cron expressions →Cron every 6 months: 0 0 1 */6 *
0 0 1 */6 * runs on the 1st of January and the 1st of July, twice a year. Any other pair of months needs a start at step or an explicit list.
Cron on 29 February: 0 0 29 2 * and the leap year rule
0 0 29 2 * runs only when 29 February exists, roughly once every four years. The century rule means 2100 has no leap day at all.
Cron macros: @daily, @weekly, @monthly and the rest
Seven macros expand to ordinary five field expressions, and @reboot has no scheduled time at all. Here is exactly what each one becomes.
Cron day of month and day of week: the OR rule
When both date fields are restricted, cron fires if either matches, not both. This turns narrowing expressions into much wider ones without any error.
Cron at a random time each day: jitter without a random field
Cron has no random field, so jitter is added in the command. A leading sleep of a random number of seconds spreads a fleet across a window.
The cron asterisk: what * means in each field
An asterisk matches every value in a field's own range, which differs per field. Why * */1 * * * is every minute and not every hour.
Tools for this
- Cron Expression Parser Free online cron expression parser - parse cron expressions and see the next scheduled run times
- Crontab Generator Free online crontab generator - build cron expressions visually with an intuitive interface