ShareYourGroupShareYourGroupCron Helper

Cron expression for the last day of the month

At 23:00, on days 28 to 31 of the month.

Five fields for Linux, GitHub Actions and Kubernetes (minute hour day month weekday). Six or seven for Quartz. Nothing you type leaves your device.

What it means and when to use it

Plain five-field cron cannot say "last day of the month". The common pattern runs the job on days 28, 29, 30 and 31, and lets a small test in the command decide whether today is really the last day: it asks for tomorrow's day of the month and proceeds only if that is 01. With GNU date the test is [ "$(date -d tomorrow +\%d)" = 01 ]. Quartz has it built in: 0 0 23 L * ? means 23:00 on the last day, and L-2 means two days before the last day.

Watch out for this

Two things must be right. First, escape the percent sign with a backslash inside a crontab, because cron turns an unescaped % into a newline (the manual describes this), which would cut your command in two. Second, date -d tomorrow is GNU syntax: it works on Linux and in Git Bash, but not on macOS, where the command is date -v+1d +%d. This was run for several dates, including 28 and 29 February 2028, and printed LAST only for the real last days.

What each field says

FieldWrittenMeans
Minute00
Hour2323
Day of month28-3128, 29, 30, 31
Month*every month
Day of week*every day of the week

An example of the next runs

If it were Friday 13 November 2026 at 10:20 UTC, the next six runs would be these. Times are shown in UTC and in India time (UTC+5:30).

UTCIndia time
Sat 28 Nov, 23:00Sun 29 Nov, 04:30
Sun 29 Nov, 23:00Mon 30 Nov, 04:30
Mon 30 Nov, 23:00Tue 1 Dec, 04:30
Mon 28 Dec, 23:00Tue 29 Dec, 04:30
Tue 29 Dec, 23:00Wed 30 Dec, 04:30
Wed 30 Dec, 23:00Thu 31 Dec, 04:30

The same schedule in other places

Quartz

Quartz has a seconds field in front, uses ? in one day field, and counts Sunday as 1:

0 0 23 28-31 * ?

GitHub Actions

Scheduled workflows run in UTC unless you add a time zone. In the workflow file:

on:
  schedule:
    - cron: '0 23 28-31 * *'

Kubernetes CronJob

In a CronJob manifest the schedule goes in spec.schedule. Without spec.timeZone, it is read in the time zone of the cluster's controller:

spec:
  schedule: "0 23 28-31 * *"
  timeZone: "Etc/UTC"

A crontab line to copy

The command is made up. Replace it with your own and use full paths:

0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = 01 ] && /home/me/bin/month-end.sh >> /home/me/month-end.log 2>&1

Questions

Does GitHub Actions support L?

No. GitHub documents the five POSIX fields only. Use days 28-31 and test the date inside the job.

What about Kubernetes?

Same: standard five fields, no L. Test the date inside the container command.

This is an independent guide and tool. It is not connected with crontab.guru, Quartz, GitHub, Kubernetes, Spring or the Linux projects named here. Product names belong to their owners.