PatternCron

Last day of the month (the safe way)

Cron has no native 'last day' syntax. This fires on the 28th through 31st and relies on a guard clause to no-op on any day but the real last one.

Last updated

Pattern
55 23 28-31 * *
Open in Crontab Schedule Creator

In plain English

  • Fires at 23:55 on the 28th, 29th, 30th and 31st
  • Needs an in-script guard to isolate the true last day

Why it’s written this way

28-31 in the day-of-month field is a range: the job launches on every one of those four dates, every month, at 23:55. That's deliberate — it's the only portable way to guarantee a hit on the true last day, since months vary between 28 and 31 days long.

The schedule alone can't finish the job: the actual 'is today the last day' decision has to live in the script itself, guarding the body with something like [ "$(date -d tomorrow +%d)" = "01" ] || exit 0 so only the genuine last-day run does anything.

Edge cases to know

  • Skip the guard clause and the job runs its full logic on the 28th, 29th, 30th AND 31st in any month with 31 days — for anything non-idempotent, like charging a card or sending an invoice, that's up to three unwanted extra runs.
  • Some schedulers support smarter 'last day' syntax directly — Vixie cron's L is nonstandard and rarely available, but systemd timers' OnCalendar do support it. Prefer the native option if the target system has one.
  • The guard shown here is GNU date syntax (date -d); BSD and macOS date need a different flag (date -v+1d), so the exact one-liner isn't portable across every box the job might end up running on.

Related in Patterns