ShareYourGroupShareYourGroupCron Helper

Cron expression for the first Monday of the month

At 09:00, on Monday.

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

Many answers online suggest 0 9 1-7 * 1 for the first Monday. It does not work, and the reason is the rule from the cron manual: when both the day-of-month field and the day-of-week field are restricted, the job runs when EITHER matches. So 0 9 1-7 * 1 runs on every day from the 1st to the 7th, and also on every Monday of the month. The correct approach is to run on every Monday (0 9 * * 1) and let the command check that the day of the month is 7 or less.

Watch out for this

The check is [ "$(date +\%d)" -le 7 ]. The percent sign needs the backslash inside a crontab. Put together: 0 9 * * 1 [ "$(date +\%d)" -le 7 ] && /home/me/bin/monthly-meeting.sh. The logic was tested on several dates: 2 November 2026, 7 December 2026 and 4 January 2027 passed as first Mondays, while 9 November and 14 December were refused. In Quartz or Spring the same schedule is a single expression: 0 0 9 ? * 2#1 (the number 2 is Monday there; the part after the hash is the first one of the month).

What each field says

FieldWrittenMeans
Minute00
Hour99
Day of month*every day of the month
Month*every month
Day of week1Mon

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
Mon 16 Nov, 09:00Mon 16 Nov, 14:30
Mon 23 Nov, 09:00Mon 23 Nov, 14:30
Mon 30 Nov, 09:00Mon 30 Nov, 14:30
Mon 7 Dec, 09:00Mon 7 Dec, 14:30
Mon 14 Dec, 09:00Mon 14 Dec, 14:30
Mon 21 Dec, 09:00Mon 21 Dec, 14: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 9 ? * 2

GitHub Actions

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

on:
  schedule:
    - cron: '0 9 * * 1'

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 9 * * 1"
  timeZone: "Etc/UTC"

A crontab line to copy

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

0 9 * * 1 [ "$(date +\%d)" -le 7 ] && /home/me/bin/monthly-meeting.sh >> /home/me/meeting.log 2>&1

Questions

How do I get the last Friday of the month in plain cron?

Run every Friday and test that the day of the month is more than 24 and that adding seven days moves to the next month, or use Quartz 6L.

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.