Cron on the Last Day of the Month
Months end on the 28th, 29th, 30th or 31st, so there is no single number for it. Quartz, Spring and AWS have L; Linux cron needs a small test.
second · minute · hour · day · month · weekday · year (optional)
Build it with controlsMonthly on the last day
In plain English
At midnight on the last day of the month.
Tap a field to see what it means.
- Next run
- —
- Usually every
- —
- Time zone
- Yours
Convert to another schedulerQuartz, Spring, AWS, GitHub Actions, Kubernetes
| Standard cron | Standard cron has no L, W or # (last day, nearest weekday, nth weekday). A common workaround is to run on the candidate days and test the date in the command. | |
|---|---|---|
| Quartz | 0 0 0 L * ? | current |
| Spring | 0 0 0 L * * | |
| AWS EventBridge | cron(0 0 L * ? *) | |
| GitHub Actions | GitHub Actions has no L, W or # (last day, nearest weekday, nth weekday). A common workaround is to run on the candidate days and test the date in the command. | |
| Kubernetes | Kubernetes has no L, W or # (last day, nearest weekday, nth weekday). A common workaround is to run on the candidate days and test the date in the command. |
About QuartzTime zone, day numbering, daylight saving
- Six or seven fields: seconds first, then minute, hour, day of month, month, day of week and an optional year.
- Day of week is 1–7 with Sunday as 1, or SUN–SAT. Write MON-FRI rather than numbers.
- One of the two day fields must be ?. L (last), W (nearest weekday) and # (nth weekday) are allowed.
- Quartz doesn’t document what happens in a skipped or repeated hour; the runs here assume skipped and once.
Sources: Quartz CronExpression.
How this works: Method, 10 sources, Checked against 3 worked examples,
How this works
Method
Quartz, Spring and AWS have a letter for it: L in the day-of-month field means the last day of the month, whether that is the 28th, 29th, 30th or 31st. 0 0 0 L * ? runs at midnight on 31 January, 28 February (29 in leap years), 31 March and so on. Full method
Sources
How it’s tested
3 worked examples for this page are checked by automated tests before every release: given the inputs, the tool must show the expected answer.
Changes
- First version: plain English and the next runs for six schedulers, a builder, conversion between them, and 20 pages for common schedules.
Worked example: 0 0 0 L * ?
Say the clock reads Monday 4 January 2027, 12:00 AM UTC. 0 0 0 L * ? means “at midnight on the last day of the month”, so the next five runs are Sunday 31 January 2027, 12:00 AM, Sunday 28 February 2027, 12:00 AM, Wednesday 31 March 2027, 12:00 AM, Friday 30 April 2027, 12:00 AM and Monday 31 May 2027, 12:00 AM.
L, and what to do without it
Quartz, Spring and AWS have a letter for it: L in the day-of-month field means the last day of the month, whether that is the 28th, 29th, 30th or 31st. 0 0 0 L * ? runs at midnight on 31 January, 28 February (29 in leap years), 31 March and so on.
Linux cron, GitHub Actions and Kubernetes have no L. The usual workaround runs on every day that could be the last, 28 to 31, and lets the command check whether tomorrow is the 1st. In a crontab, % must be escaped as \%, because cron turns a bare % into a new line.
Quartz and Spring also offer L-3 for three days before the last day and LW for the last weekday, Monday to Friday, which is handy for month-end reports.
0 0 28-31 * * [ "$(date -d tomorrow +\%d)" = 01 ] && /path/job.sh
Pitfalls
- 0 0 31 * * is not the last day: it never runs in February, April, June, September or November.
- date -d tomorrow is GNU date (Linux). On macOS and BSD, use date -v+1d +%d instead.
- In a crontab command, every % must be written \%; an unescaped % ends the command there.
- In Quartz, L in the day-of-month field means the last day of the month: day 31 for January, day 28 for February in non-leap years. Source: Quartz CronExpression.
- A % in a crontab command is turned into a newline unless escaped with a backslash. Source: POSIX crontab (IEEE Std 1003.1-2024).
“Last Day of the Month” in every scheduler
The same schedule written for each scheduler, converted and checked by this tool. A dash means that scheduler can’t express it in one expression; the note says why.
| Scheduler | Expression | Note |
|---|---|---|
| Standard Unix cron (Vixie cron, cronie) | — | Standard cron has no L, W or # (last day, nearest weekday, nth weekday). A common workaround is to run on the candidate days and test the date in the command. |
| Quartz Scheduler (Java) | 0 0 0 L * ? | |
| Spring Framework @Scheduled | 0 0 0 L * * | |
| Amazon EventBridge cron() | cron(0 0 L * ? *) | |
| GitHub Actions schedule | — | GitHub Actions has no L, W or # (last day, nearest weekday, nth weekday). A common workaround is to run on the candidate days and test the date in the command. |
| Kubernetes CronJob | — | Kubernetes has no L, W or # (last day, nearest weekday, nth weekday). A common workaround is to run on the candidate days and test the date in the command. |
Frequently Asked Questions
Does standard cron support L?
No. L, W and # are Quartz extensions, supported by Quartz, Spring and AWS EventBridge. In Linux cron, run on 28-31 and check the date in the command.
What is the last day of the month in AWS?
cron(0 0 L * ? *): L in day of month, ? in day of week, * for the year.
How do I run on the last weekday of the month?
Use LW in Quartz or Spring: 0 0 18 LW * ? runs at 6 PM on the last Monday-to-Friday day of each month.
How does the tool check leap years?
It computes the length of each month from the calendar, so February has 29 days in 2028 and 28 in 2100, which is not a leap year.