Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to schedule a Cron job to run 4th week of the year

I work on an application that uses native Unix CRON tab for scheduling jobs. the description of parameters are as follows :

Minute, Hour, Da_of_Week(1-7, 1=Sun), Day_of_Month(1-31), Day_of_Year(1-365), Week (1-52), Month (1-12) 

I want to run a job on Monday of the 1st week of the year at 8 pm, but I don't know how to determine when the week starts. Is 31 Dec 2017 - 06th Jan 2018 a first week or 7th Jan to 13th Jan 2018 a first week ?

like image 224
user2089954 Avatar asked Jan 28 '23 19:01

user2089954


1 Answers

Having cron jobs running on particular week numbers is not easy as everything depends on the definition of week numbers you are used too.

European (ISO 8601)

This ISO 8601 standard is widely used in the world: EU and most of other European countries, most of Asia, and Oceania

The ISO 8601 standard states the following:

  • There are 7 days in a week
  • The first day of the week is a Monday
  • The first week is the first week of the year which contains a Thursday. This means it is the first week with 4 days or more in January.

With this definition, it is possible to have a week number 53. These occur with the first of January is on a Friday (E.g. 2016-01-01, 2010-01-01). Or, if the year before was a leap year, also a Saturday. (E.g. 2005-01-01)

   December 2015               January 2016        
 Mo Tu We Th Fr Sa Su CW    Mo Tu We Th Fr Sa Su CW
     1  2  3  4  5  6 49                 1  2  3 53
  7  8  9 10 11 12 13 50     4  5  6  7  8  9 10 01
 14 15 16 17 18 19 20 51    11 12 13 14 15 16 17 02
 21 22 23 24 25 26 27 52    18 19 20 21 22 23 24 03
 28 29 30 31          53    25 26 27 28 29 30 31 04

American or Islamic (Not ISO 8601)

Not all countries use the ISO 8601 system. They use a more absolute approach. The American system is used in Canada, United States, New Zealand, India, Japan,... The Islamic system is generally used in the middle east. Both systems are very similar.

American:

  • There are 7 days in a week
  • The first day of the week is a Sunday
  • The first week starts on the 1st of January

Islamic:

  • There are 7 days in a week
  • The first day of the week is a Saturday
  • The first week starts on the 1st of January

With these definitions, it is possible to have partial weeks at the beginning and the end of a year. Hence the first and last week of the year could not contain all weekdays.

American:

    December 2015                January 2016       
 Su Mo Tu We Th Fr Sa CW     Su Mo Tu We Th Fr Sa CW
        1  2  3  4  5 49                     1  2 01
  6  7  8  9 10 11 12 50      3  4  5  6  7  8  9 02
 13 14 15 16 17 18 19 51     10 11 12 13 14 15 16 03
 20 21 22 23 24 25 26 52     17 18 19 20 21 22 23 04
 27 28 29 30 31       53     24 25 26 27 28 29 30 05
                             31                   06

Islamic:

   December 2015                 January 2016       
 Sa Su Mo Tu We Th Fr CW     Sa Su Mo Tu We Th Fr CW
           1  2  3  4 49                        1 01
  5  6  7  8  9 10 11 50      2  3  4  5  6  7  8 02
 12 13 14 15 16 17 18 51      9 10 11 12 13 14 15 03
 19 20 21 22 23 24 25 52     16 17 18 19 20 21 22 04
 26 27 28 29 30 31    53     23 24 25 26 27 28 29 05
                             30 31                06

Note: this could be particularly cumbersome for the task you try to perform. Especially if it has to occur on the Monday of the first week. This Monday might not exist.

Importing this in the cron

Adding these systems to the cron cannot be done in a direct way. The week testing should be done by means of a conditional test of the form

weektestcmd weeknr && cmd

For a cronjob to be run only on the Monday of the 4th week of the year at 20:00 system time (as the OP requested), the crontab would look then as:

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
# |  |  |  |  |
# *  *  *  *  *   command to be executed
  0 20  *  *  1   weektestcmd 4 && cmd

With weektestcmd defined as

ISO 8601 week numbers:

#!/usr/bin/env bash
[[ $(date '+%V') -eq $1 ]]

American calendar week numbers:

#!/usr/bin/env bash
# obtain the day of year
doy=$(date "+%j")
# compute the week offset of the first of January
## compute the day of the week with Mo=1 .. Su=7
offset=$(date -d $(date "+%Y")-01-01 "+%u")
## Take the modulo for the offset as Su=0
offset=$(( offset%7 ))
# Compute the current week number
cw=$(( (doy + offset + 6)/7 ))
[[ $cw -eq $1 ]]

Islamic calendar week numbers:

#!/usr/bin/env bash
# obtain the day of year
doy=$(date "+%j")
# compute the week offset of the first of January
## compute the day of the week with Mo=1 .. Su=7
offset=$(date -d $(date "+%Y")-01-01 "+%u")
## Take the modulo for the offset as Sa=0
offset=$(( (offset + 1)%7 ))
# Compute the current week number
cw=$(( (doy + offset + 6)/7 ))
[[ $cw -eq $1 ]]

Note: Be aware that in the American and Islamic system it might be possible not to have a Monday in week 1.

Note: There are other methods of defining a week number. Nonetheless, the approach stays the same. Define a script which checks the week number and use it in the cron.

like image 64
kvantour Avatar answered Jan 31 '23 07:01

kvantour