Blog - How to run a cron job on the first weekday of the month

Posted by

I love technical stuff and hate bad design.

I'm on Twitter.

How to run a cron job on the first weekday of the month

The first weekday of the month can fall on the 1st, 2nd or 3rd day of the month:

Month Begins First Weekday Date of First Weekday
Saturday Monday 3rd
Sunday Monday 2nd
Monday Monday 1st
Tuesday Tuesday 1st
Wednesday Wednesday 1st
Thursday Thursday 1st
Friday Friday 1st

You can see from the table that:

  • If today is a Monday, then the job should be run if today is also the 1st, 2nd, or 3rd of the month
  • If today is a Tuesday, Wednesday, Thursday, or Friday, then the job should be run if today is also the 1st of the month

The crontab records

This will run your job at 10am on the first weekday of the month:

#-- First weekday of the month

# If it's Monday, and it's the 1st, 2nd or 3rd day of the month
00 10 1-3 * * [ "$(date '+\%a')" == "Mon" ] && /path/to/your/job.sh

# If it's Tues - Friday, and the 1st of the month
00 10 1 * * [ "$(date '+\%a')" == "Tue" ] && /path/to/your/job.sh
00 10 1 * * [ "$(date '+\%a')" == "Wed" ] && /path/to/your/job.sh
00 10 1 * * [ "$(date '+\%a')" == "Thu" ] && /path/to/your/job.sh
00 10 1 * * [ "$(date '+\%a')" == "Fri" ] && /path/to/your/job.sh

#-- End first weekday of the month

Note 1: Parameters are OR

The day of month and day of week parameters are combined using OR rather than AND. If parameters were combined using AND, it would be possible to use the following crontab entries to run a command on the first weekday of the month:

00 10 1-3 * 1 /path/to/your/job.sh
00 10 1 * 2-5 /path/to/your/job.sh

The above doesn't work! Instead, the job is run on every weekday, twice on the 1st of the month, and maybe twice on the 2nd and 3rd of the month!

Note 2: Percent signs escaped

Percent signs in the crontab entry command are converted to newlines. They must be escaped using a backslash otherwise you will see an error message like this:

/bin/sh: -c: line 1: unexpected EOF while looking for matching ``'
/bin/sh: -c: line 2: syntax error: unexpected end of file

Add a comment

:
:
:

Comments

Fred de B

August 29th 21:50

Thanks for pointing to these test-lines within crontab.
Using numeric tests it might be shortened to 2 lines:

0 10 1-3 * * [ "$(date +\%w)" -eq 1 ] && /path/to/your/job.sh
0 10 1 * * [ "$(date +\%w)" -ge 2 ] && [ "$(date +\%w)" -le 5 ] && /path/to/your/job.sh

Where ...
date %w gives a numeric weekday (1=Mon ... 7=Sun)
test '-eq' is an integer equal to
test '-ge' is an integer greater than or equal to
test '-le' is an integer less than or equal to

Justin B

March 11th, 2015 21:38

Since this came up as a top result on Google, I'll add my iteration to the comments.

This will run on the first business day of the month and takes New Year's day into account. Perl regex parsing is required, thus the -P

0 12 1-4 * * date +\%b\%d\%w | /bin/grep -Pq '(?<!Jan)01[1-5]|(?<!Jan)0[23]1|Jan02[1-5]|Jan0[34]1' && echo "It's the first business day of the month!"

Adnan S

June 29th, 2014 21:52

The example above is very helpful. keep up the good work.

(kendall)

January 3rd, 2013 00:00

This will run cmd on the first business day of the month at 9 AM. Assumes POSIX grep (-q means silent operation):

0 9 1-3 * * date +\%d\%w | grep -q "01[1-5]|0[23]1" && cmd

Cheers.

SpiceMan

July 19th, 2012 05:04

found a better way

[ $(date '+%u') -le 5 ] weekday

SpiceMan

July 19th, 2012 04:01

(or LANG=C, of course)

SpiceMan

July 19th, 2012 04:00

First half of the month, only on Tuesdays and Fridays:

30 10 1-15 echo "TueFri" | grep -q "$(date '+\%a')" && cmd

Must change for locale.

For instance, I have
echo "月火水木金" | grep -q "$(date '+%a')"

in a Japanese server

Dinesh

April 19th, 2011 12:14

Thanks Joel, Your works like charm

Continue your good work. will also be useful for newbies like me.

Joel

April 19th, 2011 11:57

I don't think so, but I'm not an expert on the command line.

You can find out by trying it in your shell:

date '+%a'

If you get "Tue" back then you don't need the path.

Dinesh

April 19th, 2011 11:36

Hi, one more doubt do we need to add any path in cron for execution of "$(date '+\%a')"
== "Tue" ]

Dinesh

April 19th, 2011 11:03

Hi, Joel

Thanks, Yes i am doing this only on April 19 when. it falls on tuesday. not on every tuesdays

Joel

April 19th, 2011 10:39

By the way, are you trying to only ever do this on a Tuesday that is also the 19th April?

Joel

April 19th, 2011 10:34

Hi Dinesh, I think you are missing the && before your mkdir. Try the following:

42 14 19 04 * [ "$(date '+\%a')" == "Tue" ] && mkdir /root/test

Dinesh

April 19th, 2011 10:17

Thanks,

Its very useful, but i run this job in cron
42 14 19 04 * [ "$(date '+\%a')" == "Tue" ] mkdir /root/test

i.e a directory test has be created at 14:42 on Tue of Apr 19th but its not working for me.