CronTool
Cron expression editor & debugger

Cron expression for the last day of the month — full guide

Running a cron job on the last day of every month is one of the most common “why isn't this in standard cron?” gotchas. This guide gives you a working solution for every major scheduler: the multi-cron workaround for plain Unix crontab, the L modifier for the schedulers that support it, and full code examples for AWS, Vercel, Quartz, robfig/cron, node-cron, NCRONTAB, dragonmantank/cron-expression and Jenkins.
The 5-field POSIX crontab specification has no notion of “last day”. Modern schedulers extended the day-of-month field with 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.

Examples

  • 018***
    Every day at 18:00
  • 0*/5***
    Every 5 hours
  • 018**1-5
    Weekdays at 18:00
  • 001**
    Once a month

Cheatsheet

FieldRequiredValues RangeWildcardsminuteYes0-59, - * / hourYes0-59, - * / day of monthYes1-31, - * / L W monthYes1-12, - * /day of weekYes0-7, - * / L

Calendar

View future cron matches in a calendar

April 2026

Showing next 1000 cron schedules

Loading...

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.sh

The 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.sh

The 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

SchedulerL supportExampleGuide
POSIX crontabNomulti-cronabove
AWS EventBridgeYes (+ ? required)cron(0 0 L * ? *)AWS guide
Quartz SchedulerYes (+ ? required)0 0 0 L * ?Quartz guide
robfig/cron (Go)Yes (v3+)0 0 L * *robfig guide
NCRONTAB (Azure)Limitedmulti-cronNCRONTAB guide
dragonmantank/cron-expression (PHP)Yes0 0 L * *dragonmantank guide
JenkinsNo (use H/multi-cron)multi-cronJenkins guide
node-cronNo (5-field only)multi-cronnode-cron guide
Vercel cronNo (5-field only)multi-cronVercel guide

Common last-day-of-month patterns

  • Last day at midnight0 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.sh

Java (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 midnight

AWS CloudFormation

Resources:
  MonthEndRule:
    Type: AWS::Events::Rule
    Properties:
      ScheduleExpression: "cron(0 0 L * ? *)"
      Targets:
        - Arn: !GetAtt MonthEndLambda.Arn
          Id: MonthEndLambdaTarget

Frequently asked questions

How do I run a cron on the last day of the month in standard crontab?

Standard Unix crontab has no native 'last day' value. The portable approach uses three lines: `0 0 30 4,6,9,11 * command` for 30-day months, `0 0 31 1,3,5,7,8,10,12 * command` for 31-day months, and `0 0 28,29 2 * command` for February (with a leap-year-safe day list). On schedulers that support it, the L modifier is simpler: `0 0 L * *`.

What does the L modifier mean in cron?

L stands for 'last'. In the day-of-month field, L means 'the last day of the month' — automatically resolved to 28, 29, 30 or 31 depending on the month and year. In the day-of-week field (Quartz only), L means 'last occurrence of that weekday' (e.g. 5L is the last Friday). The L modifier is supported by Quartz, AWS EventBridge, robfig/cron, ncrontab, dragonmantank/cron-expression and several others — but not standard Unix crontab.

How do I handle leap years for last-day-of-February?

Use the L modifier if your scheduler supports it — `0 0 L * *` automatically resolves to Feb 28 in non-leap years and Feb 29 in leap years. Without L, list both days in the multi-cron approach: `0 0 28,29 2 * command`. This will fire twice in February of leap years (28th and 29th), so the script must be idempotent or check `date +%d` to skip one.

What does LW mean?

LW (last weekday) is a Quartz-specific modifier meaning 'the last weekday of the month' — the latest Mon-Fri before or equal to the actual last day. Useful for monthly accounting jobs that should never run on a Saturday or Sunday. Example: `0 0 0 LW * ?` fires at midnight on the last weekday of every month.

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.

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.

Ready to schedule it?

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.

Free forever tier ・ No credit card required

Your next schedule
GET/wp-cron.php?doing_wp_cron=1

Schedule

every 5 minutes

Next run

in 23s

Apihustle Logo

This tool is part of the Apihustle suite - a collection of tools to test, improve and get to know your API inside and out.

  • Clobbr logo

    Clobbr

    The app & CLI tool to test API endpoint speed.

    Visit
  • Crontap logo

    Crontap

    Schedule recurring API calls using cron syntax.

    Visit
  • CronTool logo

    CronTool

    Debug multiple cron expressions on a calendar.

    Visit

  • Page AI

    AI Website Generator that designs and writes clean code.

    Visit
  • Shipixen

    Generate customized boilerplates in minutes.

    Visit
  • Page UI

    Landing page UI components for React & Next.js

    Visit