/

Cron: Last Day of the Month

Standard POSIX cron has no direct way to say "last day of the month" — months have different lengths (28 to 31 days), and cron's day-of-month field only understands fixed numbers or ranges, not relative positions. The common workaround is 0 0 28-31 * * combined with a same-day check inside the job itself.

0 0 28-31 * *

Examples & Variations

0 0 28-31 * *

Runs daily 28th–31st; script checks if it's actually the last day

Try it

0 0 L * ?

Quartz Scheduler / AWS EventBridge syntax (not standard cron)

Try it

0 0 1 * *

Alternative: run on the 1st of next month instead

Try it

Common Mistakes

  • Assuming 0 0 31 * * runs on the last day of every month — it only fires in months that actually have 31 days, silently skipping February, April, June, September, and November.
  • Copying Quartz's L syntax (0 0 L * ?) into a standard Linux crontab — Vixie cron and most POSIX cron daemons don't support L at all and will reject the entry or behave unpredictably.
  • Forgetting to guard the 28-31 workaround with an actual date check — without it, the job runs on every one of those days, not just the true last day.

Best Practices

  • The most portable standard-cron workaround: schedule 0 0 28-31 * * and add a check in your script — e.g. compare tomorrow's date to see if it rolls into a new month — and exit immediately if today isn't actually the last day.
  • If your scheduler is Quartz, AWS EventBridge, or another system that supports the L character, use 0 0 L * ? directly instead of the day-range workaround — it's cleaner and unambiguous.
  • Consider whether 'first day of next month' (0 0 1 * *, run one day later) achieves the same practical goal — it's often simpler than true last-day-of-month logic.

Frequently Asked Questions

Why can't standard cron express 'last day of the month' directly?
Cron's fields only support fixed values, ranges, steps, and lists — none of which can express a relative concept like 'the final day,' since that day's number (28, 29, 30, or 31) changes depending on the month and leap year.
What is the L character in Quartz Scheduler?
Quartz (and AWS EventBridge, which uses Quartz-style cron) extends the day-of-month field with L, meaning 'last day of the month.' 0 0 L * ? runs at midnight on the last day, whatever it is that month — but this only works in Quartz-compatible schedulers, not standard Linux cron.
What's the simplest reliable workaround for standard cron?
Run daily (or on 28-31) and check the date programmatically: in most languages, adding one day to today and checking if the month changed tells you unambiguously whether today is the last day of the month.