NV ToolkitFormat · Validate · Convert

Cron example

Cron Last Day of the Month

0 0 28-31 * *

At 12:00 AM, between day 28 and 31 of the month

Open in the cron expression generator

Standard Unix cron cannot express the last day of the month. The expression above is the pattern people copy from forum answers, and on its own it is wrong: it runs on every date from the 28th to the 31st, which is up to four runs a month instead of one. Making it correct requires a guard in the command.

By NaveenKumar T · Updated · 5-field crontab expression

What each field means

Minute, hour, day of month, month, day of week — read left to right.
FieldValueMeaning
Minute0Minute 0
Hour0Hour 0
Day of month28-31Days 28–31
Month*Every month
Day of week*Every day of the week

Next 5 run times

Computing the next runs in your timezone…

What this expression really does

The day-of-month field matches any date in the range, so in January the job fires on the 28th, 29th, 30th and 31st; in April on the 28th, 29th and 30th; in a non-leap February only on the 28th. Cron has no concept of last, so it cannot know which of those dates ends the month. The plain-English translation this page shows you says exactly that, and it is worth reading before you deploy the line.

The fix is to keep the schedule and add a test to the command: run only if tomorrow is the first. On GNU coreutils that is a one-liner — [ "$(date -d tomorrow +%d)" = "01" ] && /path/to/job — and on BSD or macOS the equivalent uses date -v+1d. The scheduler fires up to four times; the guard lets exactly one of them through.

The L extension, and who has it

Several non-POSIX schedulers do support a last-day token. Quartz accepts L in the day-of-month field, along with L-3 for three days before the end and 5L for the last Friday. Spring's cron parser, croner and a number of cloud schedulers implement the same idea. If you are running on one of those, use L and delete the guard — it is unambiguous and self-documenting.

What you cannot do is assume it. Vixie cron, cronie and busybox crond will reject an L outright, and a crontab that fails to install is a job that never runs. Check your daemon's own manual page rather than a generic cron reference, because this is precisely where dialects diverge.

The better answer: run on the 1st instead

Most month-end work does not actually need to run on the last day — it needs to run after the month is over. Scheduling it at midnight on the 1st and having the job compute the previous month's date range is simpler, portable, and immune to leap years and month lengths alike.

It is also more correct in a subtle way. A job that runs at 23:00 on the 31st is summarising a month that has not finished; a job that runs at 00:05 on the 1st is summarising a month that has. If the deadline genuinely falls before midnight, keep the guard approach and document why in a comment above the crontab line.

Build a variant of this schedule with dropdowns and check the next ten runs before you install it.

Open the cron generator

Related cron examples

Browse every schedule on the cron expression generator, read the cron expression syntax guide for the rules behind the five fields, or the developer tools guides for the longer explanations.