Cron for the last day of the month
Standard cron cannot express "the last day of the month". This runs on the 28th through 31st instead, which fires up to four times — the page explains the guard clause that gets you the real behaviour.
0 0 28-31 * *
At 00:00, on the 28th through 31st of the month
Interpreted in UTC · approximately 4 runs per month
Things to check
Gotcha
Some months will be skipped
Standard cron does not clamp to the end of the month, so this skips the 30th (skipped in February) and the 31st (skipped in February, April, June, September and November) entirely rather than running on the last day.
Fix: To run on the last day of every month, schedule daily and guard the job with `[ "$(date -d tomorrow +%d)" = "01" ] || exit 0`.
Note
Interpreted in UTC
A cron expression has no timezone of its own — the scheduler's zone decides when it fires. These times are computed in UTC. The same expression on a host in another zone runs at a different moment.
Fix: Set the schedule timezone explicitly (TZ= or CRON_TZ= in crontab, `timeZone` in Kubernetes, or the scheduler's own setting). Vercel Cron Jobs always run in UTC.
Fields
- Minute
0 - At minute 0.
- Hour
0 - At 00:00.
- Day of month
28-31 - On the 28th, 29th, 30th and 31st.
- Month
* - Every month.
- Day of week
* - Every day of the week.
Next runs
- Mon, 2026-09-28, 00:00
- Tue, 2026-09-29, 00:00
- Wed, 2026-09-30, 00:00
- Wed, 2026-10-28, 00:00
- Thu, 2026-10-29, 00:00
- Fri, 2026-10-30, 00:00
- Sat, 2026-10-31, 00:00
- Sat, 2026-11-28, 00:00
Try a different expression or timezone
Times above are in UTC. Pick a timezone here to see this schedule in local time.
Call this from code or an agent
curl 'https://crontoenglish.com/api/v1/explain?expression=0%200%2028-31%20*%20*'