Skip to content
Webmaster Tools
Dev utilitiesCron ParserLast day of the month

Cron on the last day of the month

Standard cron has no last-day-of-month field. Run on days 28-31 and test whether tomorrow is the 1st, or use L on Quartz and AWS EventBridge. Lines for each platform.

Cron expression
0 0 28-31 * *
See the next run times

The short answer

Standard five-field cron can't say "the last day of the month": months end on the 28th, 29th, 30th or 31st, and no field knows which. The standard workaround is to schedule the job on every possible last day and let the command check whether tomorrow is the 1st:

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

Cron starts the line at midnight on the 28th, 29th, 30th and 31st; the test passes only on the one day that is really the last.

Field Value Meaning
Minute 0 at minute 0
Hour 0 at midnight
Day of month 28-31 the 28th to the 31st
Month * every month
Day of week * any day of the week

How the test works

  • date -d tomorrow +%d prints tomorrow's day of the month. If it's 01, today is the last day.
  • In a crontab, % must be written \%: cron treats a bare % as a newline and cuts the command there. That's the usual reason this line "does nothing".
  • -d tomorrow is GNU date (Linux). On macOS and BSD use date -v+1d +%d.

Midnight on the last day is the start of that day. For a month-end job that should see the whole month, run late in the day (55 23 28-31 * * with the same test) or run on the 1st instead with 0 0 1 * *, processing the previous month.

Where L works

Quartz-style schedulers and AWS have a real last-day marker:

  • AWS EventBridge: cron(0 0 L * ? *). L in the day-of-month field is the last day of the month.
  • Quartz (Java, Spring's Quartz integration, many enterprise schedulers): 0 0 0 L * ? (Quartz has a seconds field first).
  • Not supported: classic crontab, GitHub Actions and Kubernetes CronJob reject L. Spring's own @Scheduled cron does accept it.

Variants

Schedule Expression
Last day at 23:00 0 23 28-31 * * plus the test
Last day of each quarter 0 23 28-31 3,6,9,12 * plus the test
The day before the last 0 0 27-30 * * with -d '+2 days' in the test
First day of the month 0 0 1 * *
1st and 15th 0 0 1,15 * *

Where to write it

  • crontab: the line with the test, as above.
  • GitHub Actions: cron: '0 0 28-31 * *' (UTC) and a first step that checks [ "$(date -u -d tomorrow +%d)" = 01 ] (no escaping outside crontab), with an if: on the real job so it runs only when that check passes.
  • Kubernetes CronJob: schedule: "0 0 28-31 * *" with timeZone:, and the test at the start of the container's command.
  • AWS EventBridge: cron(0 0 L * ? *), no test needed.

Look at the candidate days in the Cron Expression Parser.