If for some reason you want to run cron in last day of month you would likely need 3 separate cron schedule expressions:
0 0 31 1,3,5,7,8,10,12 * some-command
# or
0 0 31 JAN,MAR,MAY,JUL,AUG,OCT,DEC * some-command
0 0 30 4,6,9,11 * some-command
# or
0 0 30 APR,JUN,SEP,NOV * some-command
We can use date -d tomorrow +%d
command which will return 1 if tomorrow is the day of next month:
0 0 28,29 2 * [ $(date -d tomorrow +%d) -eq 1 ] && some-command
# or
0 0 28,29 FEB * [ $(date -d tomorrow +%d) -eq 1 ] && some-command
This one is going to be tricky as cron runs in sh
instead of bash
, we are going to use arithmetic expansion here $((2 + 2))
.
Difference from bash version that we can't put two expressions in one as ,
is not available.
# sets $year to current year
year=$(date +%Y)
# year is leap if divisible by 400 or divisible by 4 but at the same time not divisible by 100
# arithmetic expansion returns 1 on true and 0 on false
# will run on leap year
[ $((year % 400 == 0 || year % 4 == 0 && year % 100 != 0)) -eq 1 ]
# will run on non-leap year
[ $((year % 400 == 0 || year % 4 == 0 && year % 100 != 0)) -eq 0 ]
# so, instead of making 2 separate cron tasks for 28th and 29th we can do a bit different condition:
# since expansion returns 1 on leap year adding 28 to it will result in 29
# and on non-leap year, 0 + 28 = 28, comparing sum with current day will
[ $(((year % 400 == 0 || year % 4 == 0 && year % 100 != 0) + 28)) -eq $(date +%d) ]
Here's result: (in cron %
have to be escaped \%
)
0 0 28,29 2 * year=$(date +\%Y); [ $(((year \% 400 == 0 || year \% 4 == 0 && year \% 100 != 0) + 28)) -eq $(date +\%d) ] && some-command
# or
0 0 28,29 FEB * year=$(date +\%Y); [ $(((year \% 400 == 0 || year \% 4 == 0 && year \% 100 != 0) + 28)) -eq $(date +\%d) ] && some-command
Using previous approach all the previous cron expressions can be replaced with one:
0 0 28-31 * * [ $(date -d tomorrow +%d) -eq 1 ] && some-command
Since running it every day would be useless, setting range to 28-31 would be the most optimal in scope on one expression.
0 0 28,29 2 * [ $(date -d tomorrow +%d) -eq 1 ] && some-command
0 0 30-31 1,3-12 * [ $(date -d tomorrow +%d) -eq 1 ] && some-command
#or
0 0 28,29 FEB * [ $(date -d tomorrow +%d) -eq 1 ] && some-command
0 0 30-31 JAN,MAR-DEC * [ $(date -d tomorrow +%d) -eq 1 ] && some-command