Run Jobs on the Last Day of the Month at 9 AM | CronBase

cron expression Standard
$ 0 9 L * *

At nine o'clock in the morning on the last day of every month

The `0 9 L * *` cron expression schedules a task to run precisely at nine AM on the final day of every month, regardless of whether the month has twenty-eight, thirty, or thirty-one days. It is commonly used for generating monthly financial statements, processing end-of-month billing cycles, and compiling aggregate usage reports.

Minute
0
Hour
9
Day of Month
L
Month
*
Day of Week
*
How it works

* Tools

Code & Implementations

Bash
#!/usr/bin/env bash
set -euo pipefail

# This script is designed to run daily at 9:00 AM via standard cron: 0 9 28-31 * *
# It acts as a safety wrapper for environments where 'L' is not natively supported.

is_last_day_of_month() {
    # Check if tomorrow's day of the month is 01
    [[ "$(date -d "tomorrow" +%d)" -eq "01" ]]
}

if ! is_last_day_of_month; then
    echo "Today is not the last day of the month. Exiting gracefully."
    exit 0
fi

echo "Starting end-of-month execution at $(date)"
/usr/local/bin/run-monthly-reports.sh
Setup notes

Save this script to /usr/local/bin/monthly-wrapper.sh, make it executable with 'chmod +x', and schedule it in crontab using '0 9 28-31 * * /usr/local/bin/monthly-wrapper.sh'.

Last verified:

Partner BetterStack

Monitor this schedule in production

Get alerted the moment this cron job fails, is late, or doesn't run. BetterStack tracks execution, duration, and output — no infrastructure required.

Platform Equivalents

Systemd Timer

OnCalendar*-*-* 09:00:00

my-task.timer
[Unit]
Description=Timer for cron expression: 0 9 L * *

[Timer]
OnCalendar=*-*-* 09:00:00
Persistent=true

[Install]
WantedBy=timers.target

Last verified:

Frequently Asked Questions

What happens if my cron engine does not support the 'L' character?

If your cron engine (like standard Linux crontab) does not support 'L', you must schedule the job to run daily from the 28th to the 31st using '0 9 28-31 * *' and prepend a date validation command to ensure the script only executes if tomorrow is the 1st.

How does Daylight Saving Time (DST) affect a 9:00 AM monthly execution?

If your server runs on local time zones that observe DST, the job will shift relative to UTC. To guarantee consistent 24-hour intervals and prevent reporting anomalies, run your server and cron daemon in Coordinated Universal Time (UTC).

Is '0 9 L * *' supported natively in Kubernetes CronJobs?

No, Kubernetes uses the Go-based robfig/cron parser, which does not support the 'L' wildcard. You must implement a workaround, such as scheduling the job daily between the 28th and 31st and evaluating the date inside your container entrypoint.

How can I prevent database connection pool exhaustion during this end-of-month run?

Because monthly jobs process high volumes of data, isolate the database pool for this job. Implement strict timeouts, limit concurrent queries, and use cursor-based batching instead of loading all monthly transaction records into memory at once.

How do I schedule this in Quartz or Spring Scheduler?

In Quartz and Spring, you must use a 6-field cron syntax and replace the day-of-week field with a question mark to avoid conflicts. The correct expression is '0 0 9 L * ?' to run at exactly 9:00:00 AM on the last day of every month.

* Explore

Related expressions you might need

Last verified:

Was this helpful?