Cron expression for the last day of the month - full guide
At 04:30, every day.
Next runs · UTC
- —
- —
- —
- —
- —
Calendar
September 2026 · UTC
0 runs
About this tool
L, which auto-resolves to 28 / 29 / 30 / 31 depending on the month and year. If your runtime supports L, use it - it's the cleanest answer. If not, the multi-cron pattern below works anywhere.Standard crontab - the multi-cron workaround
POSIX crontab has no last-day token, so you simulate it by enumerating the actual last day of each month. There are three groups: 30-day months, 31-day months, and February.
# 30-day months: April, June, September, November
0 0 30 4,6,9,11 * /path/to/script.sh
# 31-day months
0 0 31 1,3,5,7,8,10,12 * /path/to/script.sh
# February (leap-year safe - fires both 28th and 29th in leap years)
0 0 28,29 2 * /path/to/script.shThe leap-year line is the trickiest. In non-leap years, only the 28th exists, so the cron fires once. In leap years, both the 28th and 29th exist; cron fires on both. To fire only on the actual last day, gate the script:
0 0 28,29 2 * [ "$(date -d tomorrow +%d)" = "01" ] && /path/to/script.shThe wrapper checks “is tomorrow the 1st?”. Only on the actual last day of February (28th in non-leap, 29th in leap) is the answer yes.
Extended cron - the L modifier
Schedulers with extended cron support (Quartz, AWS EventBridge, robfig/cron, ncrontab, dragonmantank/cron-expression and several others) accept L in the day-of-month field. L auto-resolves to the last day of the current month - 28 / 29 / 30 / 31 - without you enumerating anything.
# Quartz / AWS EventBridge: midnight on the last day of every month
0 0 L * * (Quartz 6-field, but Quartz needs ?)
0 0 0 L * ? (Quartz 6-field with seconds and ? in day-of-week)
cron(0 0 L * ? *) (AWS EventBridge)
0 0 L * * (robfig/cron with cron.WithLocation)The exact form differs per implementation. Quartz forbids both day-of-month and day-of-week being values, so one of them must be ?. AWS EventBridge has the same rule and additionally requires a year field. The dedicated guides for each library cover the platform-specific syntax in detail.
Last-day-of-month support by scheduler
| Scheduler | L support | Example | Guide |
|---|---|---|---|
| POSIX crontab | No | multi-cron | above |
| AWS EventBridge | Yes (+ ? required) | cron(0 0 L * ? *) | AWS guide |
| Quartz Scheduler | Yes (+ ? required) | 0 0 0 L * ? | Quartz guide |
| robfig/cron (Go) | Yes (v3+) | 0 0 L * * | robfig guide |
| NCRONTAB (Azure) | Limited | multi-cron | NCRONTAB guide |
| dragonmantank/cron-expression (PHP) | Yes | 0 0 L * * | dragonmantank guide |
| Jenkins | No (use H/multi-cron) | multi-cron | Jenkins guide |
| node-cron | No (5-field only) | multi-cron | node-cron guide |
| Vercel cron | No (5-field only) | multi-cron | Vercel guide |
Common last-day-of-month patterns
- Last day at midnight -
0 0 L * *or the multi-cron triplet above. - Last weekday of the month - Quartz only:
0 0 0 LW * ?. Useful for monthly accounting that must run on a business day. - Last Friday of the month - Quartz:
0 0 12 ? * 6L(1=Sunday, so 6=Friday). - First and last day of the month - list:
0 0 1,L * *(where L is supported), or two separate cron lines. - Two days before the last day - Quartz:
0 0 0 L-2 * ?. Other dialects don't accept arithmetic on L.
Code snippets per language
Bash / crontab
# Run nightly, exit unless tomorrow is the 1st.
0 0 28-31 * * [ "$(date -d tomorrow +%d)" = "01" ] && /path/to/script.shJava (Quartz)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("monthEndTrigger")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 L * ?"))
.build();Go (robfig/cron)
c := cron.New(cron.WithParser(cron.NewParser(
cron.SecondOptional | cron.Minute | cron.Hour |
cron.Dom | cron.Month | cron.Dow | cron.Descriptor)))
c.AddFunc("0 0 L * *", monthEndJob)
c.Start()PHP (dragonmantank/cron-expression)
use Cron\CronExpression;
$cron = new CronExpression('0 0 L * *');
$next = $cron->getNextRunDate(); // DateTime of last day of month at midnightAWS CloudFormation
Resources:
MonthEndRule:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: "cron(0 0 L * ? *)"
Targets:
- Arn: !GetAtt MonthEndLambda.Arn
Id: MonthEndLambdaTargetExamples
- 0 18 * * *Every day at 18:00
- 0 */5 * * *Every 5 hours
- 0 18 * * 1-5Weekdays at 18:00
- 0 0 1 * *Once a month, on the 1st at midnight
Cheatsheet
Full cheatsheet| Field | Req. | Range | Wildcards |
|---|---|---|---|
| minute | yes | 0-59 | , - * / |
| hour | yes | 0-23 | , - * / |
| day of month | yes | 1-31 | , - * / |
| month | yes | 1-12 or JAN-DEC | , - * / |
| day of week | yes | 0-6 or names; some dialects use 0-7 or 1-7 — see Dialects | , - * / |
Frequently asked questions
Syntax
How do I run a cron on the last day of the month in standard crontab?
Use 0 0 28-31 * * plus a runtime test that tomorrow is day 1. Standard crontab has no last-day token; separate 30- and 31-day entries work, but 28,29 for February runs twice in leap years unless guarded.
What does the L modifier mean in cron?
L means “last.” In day-of-month it selects the month's final date; in day-of-week it can select a weekday's final occurrence. Quartz, AWS, Spring, recent node-cron, and dragonmantank support it; Vixie cron, robfig/cron, and NCrontab do not.
What's the difference between 'last day of month' and 'end of month'?
They're the same calendar concept but the cron syntax differs by scheduler. Quartz / AWS use L for the last day. Some libraries also expose LW for last weekday and L-1 for second-to-last day. 'End of month' is informal - there's no EOM token in any major scheduler.
Days and months
How do I handle leap years for last-day-of-February?
Use L when your scheduler supports it; it resolves to February 28 or 29 automatically. Without L, schedule candidate dates and run only when tomorrow is day 1. A bare 28,29 list fires twice in leap-year Februaries.
What does LW mean?
LW means the last weekday of the month: the final Monday-to-Friday date. Quartz uses 0 0 0 LW * ?; recent node-cron and dragonmantank/cron-expression also support LW in their documented five-field forms.
How do I run a job on the first AND last day of the month?
With L support, two lines: 0 0 1 * * command (first day) and 0 0 L * * command (last day). Or one line if your scheduler accepts comma-separated day-of-month: 0 0 1,L * *. Without L, fall back to the multi-cron month-length enumeration.
How do I run a job on the last Friday of every month?
Quartz: 0 0 12 ? * 6L (Quartz day-of-week 1=Sunday, so 6=Friday). AWS EventBridge: cron(0 12 ? * 6L *). Without L-modifier support, you have to enumerate the days that could be the last Friday (24-30 of each month) and check the weekday in the script.
Timezones and DST
Which timezone determines the last day of the month?
The scheduler's configured timezone determines the calendar boundary. Evaluate any shell or application check in that same timezone to avoid disagreement around midnight.
Can DST affect a month-end cron job?
Yes. A local wall-clock time can be skipped or repeated during a transition. Pick a stable hour, use UTC when appropriate, and make the month-end operation idempotent.
Platforms
What is the portable Vixie cron last-day pattern?
On GNU date systems, use 0 0 28-31 * * [ "$(date +%d -d tomorrow)" = "01" ] && command. The date -d tomorrow option is GNU-specific; BSD and macOS require a different tomorrow-date calculation.
Which schedulers support L for the last day of a month?
Quartz, AWS EventBridge, Spring, recent node-cron versions, and dragonmantank/cron-expression support L. Vixie cron, robfig/cron v3, and NCrontab require a runtime or shell check.
What is the last-day syntax in recent node-cron versions?
Use 0 0 L * * for midnight on the last day. Confirm the installed node-cron version because older releases did not expose the same extended operators.
What is the PHP dragonmantank last-day syntax?
Use 0 0 L * *. The PHP parser used by Laravel understands L and resolves the correct final date, including leap years.
Debugging
How do I prevent duplicate month-end processing?
Use a lock plus an idempotency key based on the target month. The lock prevents concurrent runs, while the key protects retries and duplicate scheduler delivery.
Crontap
Can Crontap run a last-day-of-month job?
Yes. You can run a compatible last-day expression or schedule a daily HTTP check on Crontap, depending on the dialect used by the receiving system.
Write the cron here. Run it on Crontap.
Point Crontap at any URL. Pick any cron. Done.
WordPress, Shopify, Railway, Cloud Run, Vercel, HubSpot, Ghost, your own box. If it answers HTTP, Crontap can drive it on a clock you can read, in the timezone that actually matters, and page you when something breaks.
1.9k+ teams · Free forever tier · No credit card