PatternCron

First day of every month

Monthly reports and invoice runs: 09:00 on the 1st of each month — and why "last day of the month" is famously harder.

Last updated

Pattern
0 9 1 * *
Open in Crontab Schedule Creator

In plain English

  • Fires at 09:00 on the 1st of every month
  • 12 runs per year

Why it’s written this way

Minute 0, hour 9, day-of-month 1, any month, any weekday: the morning of the 1st, twelve times a year. Day-of-week stays * so the schedule is calendar-driven regardless of which weekday the 1st lands on.

Edge cases to know

  • →"Last day of the month" has no portable five-field spelling — months end on 28, 29, 30 or 31. Either run 0 9 28-31 * * with a script guard checking tomorrow is the 1st, or use a scheduler with L syntax (Quartz).
  • →Combining a restricted day-of-month with a restricted day-of-week ("first Monday") fires on EITHER match in classic cron — that one needs a script guard too.
  • →Month-end billing jobs usually want the 1st looking BACK at last month, which this is; running ON the last day adds the pitfalls above for little gain.

Part by part

0 9
Minute 0 of hour 9 — nine in the morning, so the run lands during the working day when someone is around to notice it fail.
1
Day-of-month, fixed to the first. This is the field that makes the schedule monthly.
* *
Month and day-of-week, both unrestricted. The day-of-week wildcard is load-bearing here, for the reason set out below.

Common mistakes

  • 0 9 1 * 1

    The trap that catches almost everyone. Restricting day-of-month and day-of-week together does not mean "the first of the month, if it is a Monday" — classic cron ORs the two, so this runs on the 1st AND on every Monday.

    0 9 1 * *
  • 0 9 31 * *

    The 31st does not exist in seven months of the year, so the job runs five times annually rather than twelve. The last day of the month cannot be expressed in cron at all — the usual workaround is to run daily and let the script check.

  • 0 9 1 1 *

    Fixing the month as well makes it annual, not monthly. It is a single character between a job that runs twelve times a year and one that runs once.

Questions

How do I run on the first Monday of the month instead?

Cron cannot express it, because of the OR rule between day-of-month and day-of-week. The standard approach is to schedule 0 9 1-7 * * and have the script exit immediately unless today is a Monday — the date range guarantees the first occurrence falls inside it.

Why does adding a day-of-week widen the schedule instead of narrowing it?

Because when both day fields are restricted, cron treats them as alternatives rather than as conditions to satisfy together. It is documented behaviour rather than a bug, and it surprises nearly everyone the first time.

How do I schedule the last day of the month?

Not in cron directly. Run the job daily and have it exit unless tomorrow is the first — a single date comparison in the script. Attempting it with 28-31 in the day field produces multiple runs in most months.

Does the month field accept names?

In Vixie cron, yes: JAN through DEC work in the month field just as day names do in the day-of-week field. Both are more readable and both are less portable than the numeric forms.

Related in Patterns