DevToolsmith

Cron Job on the Last Day of the Month

Standard cron can’t express “On the last day of the month” in a single expression. Here is the closest schedule, 55 23 28-31 * *, plus the workaround that fills the gap and copy-ready examples.

Runs 100% in your browser — nothing is uploaded

Cron schedule

Schedule time zone

UTC

Closest cron expression

55 23 28-31 * *

At 23:55, between day 28 and 31 of the month. On its own, it runs on 41 days a year.

Standard cron has no “last day” symbol. Quartz’s L isn’t supported by crontab, Kubernetes or GitHub Actions. The usual fix is to schedule the job on every day that could be the last one, the 28th to the 31st, and let the command check whether tomorrow is the 1st.

Workaround: run a job on the last day of the month

This uses GNU date (Linux). On macOS or BSD, replace date -d tomorrow with date -v+1d.

crontab
55 23 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/job.sh

The same idea works on every scheduler below: keep the base schedule and put the check at the start of the job’s command or script.

Field by field

FieldValueMatches
minute 55 55
hour 23 23
day of month 28-31 28–31
month * every value
day of week * every value

Examples

crontab

Run crontab -e and add:

55 23 28-31 * * /usr/local/bin/job.sh >> /var/log/job.log 2>&1

For the exact schedule, use the workaround line above instead.

Kubernetes CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: my-job
spec:
  schedule: "55 23 28-31 * *"
  timeZone: "Etc/UTC"          # Kubernetes 1.27+
  concurrencyPolicy: Forbid    # skip a run if the last one is still going
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: job
              image: ghcr.io/acme/job:1.0
          restartPolicy: OnFailure

GitHub Actions

on:
  schedule:
    - cron: '55 23 28-31 * *'   # UTC

GitHub evaluates schedules in UTC, and runs can start several minutes late at busy times.

systemd timer

# /etc/systemd/system/job.timer
[Unit]
Description=Run job.service on the last day of the month

[Timer]
OnCalendar=*-*-28..31 23:55:00
Persistent=true

[Install]
WantedBy=timers.target

Enable it with systemctl enable --now job.timer, and check the next runs with systemd-analyze calendar "*-*-28..31 23:55:00". Persistent=true runs a missed job after downtime, which cron can’t do.

AWS EventBridge

cron(55 23 28-31 * ? *)

EventBridge cron has six fields (the last is the year), uses ? in either the day-of-month or the day-of-week field, and numbers weekdays from 1 (Sunday) to 7. Rules run in UTC; EventBridge Scheduler also accepts a time zone.

Similar schedules: monthly and yearly

Have a different schedule? Paste any expression into the Cron Expression Generator, or browse all cron examples.

Sources

Spotted a mistake? Email hello@devtoolsmith.com and we’ll fix it.

Frequently asked questions

How do I run a cron job on the last day of the month?

No single standard cron expression does this exactly. Standard cron has no “last day” symbol. Quartz’s L isn’t supported by crontab, Kubernetes or GitHub Actions. The usual fix is to schedule the job on every day that could be the last one, the 28th to the 31st, and let the command check whether tomorrow is the 1st. This uses GNU date (Linux). On macOS or BSD, replace date -d tomorrow with date -v+1d. 55 23 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/job.sh