Classic five-field cron has no value for "the last day of the month". In RunLater, put L in the day-of-month field: 0 9 L * * runs at 09:00 on November 30, December 31, January 31 and February 28 (29 in leap years). A Linux crontab does not accept L, so there you run on days 28 to 31 and let a date check skip every day that is not the last.
Expressions that work in RunLater
| Expression | Runs |
|---|---|
0 9 L * * | 09:00 on the last day of every month |
30 23 L * * | 23:30 on the last day, for end-of-month reports and invoices |
0 0 L 3,6,9,12 * | 00:00 on March 31, June 30, September 30 and December 31 (end of each quarter) |
0 9 * * 5L | 09:00 on the last Friday of every month |
The day is worked out in the timezone you set on the request, so "23:30 on the last day" means 23:30 in that zone, not on a server clock. More on that in the timezone guide.
In a Linux crontab
Run on the last four possible days and continue only when tomorrow is the 1st:
# GNU date (most Linux)
0 9 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/month-end.sh
# BSD / macOS date
0 9 28-31 * * [ "$(date -v+1d +\%d)" = "01" ] && /usr/local/bin/month-end.shThe % signs need a backslash: in a crontab line an unescaped % ends the command and starts its standard input, and the job quietly does the wrong thing.
Or do the check in your endpoint
If the job is a URL, the same trick works in code: schedule 0 9 28-31 * * and return early unless tomorrow is the 1st in your timezone.
const tz = 'America/Chicago';
const tomorrow = new Date(Date.now() + 24 * 60 * 60 * 1000);
const day = new Intl.DateTimeFormat('en-US', { timeZone: tz, day: 'numeric' }).format(tomorrow);
if (day !== '1') return Response.json({ skipped: true });
// ... month-end workWith RunLater you can skip this and use L directly. To check it, paste 0 9 L * * into the cron expression explainer for the next run dates in your timezone.
Related schedules
- First day of every month:
0 0 1 * * - First Monday, second Tuesday or last Friday of the month
- The full cron expression guide
Frequently asked questions
What is the cron expression for the last day of the month?
0 9 L * * runs at 09:00 on the last day of every month, in schedulers that support L, including RunLater. Standard Linux crontab does not accept L; use 0 9 28-31 * * with a check that tomorrow is the 1st.
Does L handle February and leap years?
Yes. L means the last day of that month, so it runs on February 28, or February 29 in a leap year, and on the 30th or 31st in other months.
Can cron run on the last weekday or last business day of the month?
Not with RunLater or standard crontab: the LW modifier is not supported. Run on weekdays (0 9 * * 1-5) and have the job exit unless the next weekday falls in the next month.
Why not just use 0 9 31 * *?
Day 31 only exists in seven months, so that line skips February, April, June, September and November.