Combining cron schedules spread over 2 months - cron

I have a cron task I want to schedule to run every day at 10am from 20th November to 10th December.
I'm doing this by scheduling the task twice, one from 20th November to 30th November (0 0 10 20-30 NOV ?) and again from 1st December to 10th December (0 0 10 1-10 DEC ?).
Is there any way to combine "0 0 10 20-30 NOV ?" and "0 0 10 1-10 DEC ?" together so I can have just one task and achieve the same functionality?

According to crontab.guru, these schedules can't be combined. But you could schedule it for every day and have your command make sure it's only running between those dates.
0 10 * 11,12 * TODAY=`date +"%m%d"`; [ $TODAY -ge 1120 -a $TODAY -le 1210 ] && rest_of_your_command
Today (October 23rd), the value of TODAY would be 1023 which is not between 1120 and 1210, so your command wouldn't run.

Related

how to set up a cronjob to run on the last sunday of each month? [duplicate]

I need to create a CRON job that will run on the last day of every month.
I will create it using cPanel.
Any help is appreciated.
Thanks
Possibly the easiest way is to simply do three separate jobs:
55 23 30 4,6,9,11 * myjob.sh
55 23 31 1,3,5,7,8,10,12 * myjob.sh
55 23 28 2 * myjob.sh
That will run on the 28th of February though, even on leap years so, if that's a problem, you'll need to find another way.
However, it's usually both substantially easier and correct to run the job as soon as possible on the first day of each month, with something like:
0 0 1 * * myjob.sh
and modify the script to process the previous month's data.
This removes any hassles you may encounter with figuring out which day is the last of the month, and also ensures that all data for that month is available, assuming you're processing data. Running at five minutes to midnight on the last day of the month may see you missing anything that happens between then and midnight.
This is the usual way to do it anyway, for most end-of-month jobs.
If you still really want to run it on the last day of the month, one option is to simply detect if tomorrow is the first (either as part of your script, or in the crontab itself).
So, something like:
55 23 28-31 * * [[ "$(date --date=tomorrow +\%d)" == "01" ]] && myjob.sh
should be a good start, assuming you have a relatively intelligent date program.
If your date program isn't quite advanced enough to give you relative dates, you can just put together a very simple program to give you tomorrow's day of the month (you don't need the full power of date), such as:
#include <stdio.h>
#include <time.h>
int main (void) {
// Get today, somewhere around midday (no DST issues).
time_t noonish = time (0);
struct tm *localtm = localtime (&noonish);
localtm->tm_hour = 12;
// Add one day (86,400 seconds).
noonish = mktime (localtm) + 86400;
localtm = localtime (&noonish);
// Output just day of month.
printf ("%d\n", localtm->tm_mday);
return 0;
}
and then use (assuming you've called it tomdom for "tomorrow's day of month"):
55 23 28-31 * * [[ "$(tomdom)" == "1" ]] && myjob.sh
Though you may want to consider adding error checking since both time() and mktime() can return -1 if something goes wrong. The code above, for reasons of simplicity, does not take that into account.
There's a slightly shorter method that can be used similar to one of the ones above. That is:
[ $(date -d +1day +%d) -eq 1 ] && echo "last day of month"
Also, the crontab entry could be update to only check on the 28th to 31st as it's pointless running it the other days of the month. Which would give you:
0 23 28-31 * * [ $(date -d +1day +%d) -eq 1 ] && myscript.sh
What about this one, after Wikipedia?
55 23 L * * /full/path/to/command
For AWS Cloudwatch cron implementation (Scheduling Lambdas, etc..) this works:
55 23 L * ? *
Running at 11:55pm on the last day of each month.
Adapting paxdiablo's solution, I run on the 28th and 29th of February. The data from the 29th overwrites the 28th.
# min hr date month dow
55 23 31 1,3,5,7,8,10,12 * /path/monthly_copy_data.sh
55 23 30 4,6,9,11 * /path/monthly_copy_data.sh
55 23 28,29 2 * /path/monthly_copy_data.sh
You could set up a cron job to run on every day of the month, and have it run a shell script like the following. This script works out whether tomorrow's day number is less than today's (i.e. if tomorrow is a new month), and then does whatever you want.
TODAY=`date +%d`
TOMORROW=`date +%d -d "1 day"`
# See if tomorrow's day is less than today's
if [ $TOMORROW -lt $TODAY ]; then
echo "This is the last day of the month"
# Do stuff...
fi
For a safer method in a crontab based on #Indie solution (use absolute path to date + $() does not works on all crontab systems):
0 23 28-31 * * [ `/bin/date -d +1day +\%d` -eq 1 ] && myscript.sh
Some cron implementations support the "L" flag to represent the last day of the month.
If you're lucky to be using one of those implementations, it's as simple as:
0 55 23 L * ?
That will run at 11:55 pm on the last day of every month.
http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger
#########################################################
# Memory Aid
# environment HOME=$HOME SHELL=$SHELL LOGNAME=$LOGNAME PATH=$PATH
#########################################################
#
# string meaning
# ------ -------
# #reboot Run once, at startup.
# #yearly Run once a year, "0 0 1 1 *".
# #annually (same as #yearly)
# #monthly Run once a month, "0 0 1 * *".
# #weekly Run once a week, "0 0 * * 0".
# #daily Run once a day, "0 0 * * *".
# #midnight (same as #daily)
# #hourly Run once an hour, "0 * * * *".
#mm hh Mday Mon Dow CMD # minute, hour, month-day month DayofW CMD
#........................................Minute of the hour
#| .................................Hour in the day (0..23)
#| | .........................Day of month, 1..31 (mon,tue,wed)
#| | | .................Month (1.12) Jan, Feb.. Dec
#| | | | ........day of the week 0-6 7==0
#| | | | | |command to be executed
#V V V V V V
* * 28-31 * * [ `date -d +'1 day' +\%d` -eq 1 ] && echo "Tomorrow is the first today now is `date`" >> ~/message
1 0 1 * * rm -f ~/message
* * 28-31 * * [ `date -d +'1 day' +\%d` -eq 1 ] && echo "HOME=$HOME LOGNAME=$LOGNAME SHELL = $SHELL PATH=$PATH"
Set up a cron job to run on the first day of the month. Then change the system's clock to be one day ahead.
I found out solution (On the last day of the month) like below from this site.
0 0 0 L * ? *
CRON details:
Seconds Minutes Hours Day Of Month Month Day Of Week Year
0 0 0 L * ? *
To cross verify above expression, click here which gives output like below.
2021-12-31 Fri 00:00:00
2022-01-31 Mon 00:00:00
2022-02-28 Mon 00:00:00
2022-03-31 Thu 00:00:00
2022-04-30 Sat 00:00:00
00 23 * * * [[ $(date +'%d') -eq $(cal | awk '!/^$/{ print $NF }' | tail -1) ]] && job
Check out a related question on the unix.com forum.
You can just connect all answers in one cron line and use only date command.
Just check the difference between day of the month which is today and will be tomorrow:
0 23 * * * root [ $(expr $(date +\%d -d '1 days') - $(date +\%d) ) -le 0 ] && echo true
If these difference is below 0 it means that we change the month and there is last day of the month.
55 23 28-31 * * echo "[ $(date -d +1day +%d) -eq 1 ] && my.sh" | /bin/bash
What about this?
edit user's .bashprofile adding:
export LAST_DAY_OF_MONTH=$(cal | awk '!/^$/{ print $NF }' | tail -1)
Then add this entry to crontab:
mm hh * * 1-7 [[ $(date +'%d') -eq $LAST_DAY_OF_MONTH ]] && /absolutepath/myscript.sh
In tools like Jenkins, where usually there is no support for L nor tools similar to date, a cool trick might be setting up the timezone correctly. E.g. Pacific/Kiritimati is GMT+14:00, so if you're in Europe or in the US, this might do the trick.
TZ=Pacific/Kiritimati \n H 0 1 * *
Result: Would last have run at Saturday, April 30, 2022 10:54:53 AM GMT; would next run at Tuesday, May 31, 2022 10:54:53 AM GMT.
Use the below code to run cron on the last day of the month in PHP
$commands = '30 23 '.date('t').' '.date('n').' *';
The last day of month can be 28-31 depending on what month it is (Feb, March etc). However in either of these cases, the next day is always 1st of next month. So we can use that to make sure we run some job always on the last day of a month using the code below:
0 8 28-31 * * [ "$(date +%d -d tomorrow)" = "01" ] && /your/script.sh
Not sure of other languages but in javascript it is possible.
If you need your job to be completed before first day of month node-cron will allow you to set timezone - you have to set UTC+12:00 and if job is not too long most of the world will have results before start of their month.
If the day-of-the-month field could accept day zero that would very simply solve this problem. Eg. astronomers use day zero to express the last day of the previous month. So
00 08 00 * * /usr/local/sbin/backup
would do the job in simple and easy way.
Better way to schedule cron on every next month of 1st day
This will run the command foo at 12:00AM.
0 0 1 * * /usr/bin/foo
Be cautious with "yesterday", "today", "1day" in the 'date' program if running between midnight and 1am, because often those really mean "24 hours" which will be two days when daylight saving time change causes a 23 hour day. I use "date -d '1am -12 hour' "

Cron Expression for every second Monday of the month (for Hangfire)

I am trying to create recurring job in hangfire that runs, once a month at the second Monday, something like this:
1. Monday, May 14, 2018 8:00 AM
2. Monday, June 11, 2018 8:0 AM
3. Monday, July 9, 2018 8:00 AM
4. Monday, August 13, 2018 8:00 AM
5. Monday, September 10, 2018 8:00 AM
I have found this answer in stackoverflow, but since this is not a standard cron for scheduling hangifre jobs I can not use it.
My question is can I make an expression like this using the format
* * * * * (min hour day/month month day/week)
The following command seems to work for me.
0 8 ? * MON#2
Assuming that you want this job to execute at 8 AM the second Monday of each month, the # character allows you to specify the "nth" day of any given month. We use the ? character in the day/month row since we are fine with any numeric day as long as it is the second Monday.
Read more about special characters here: http://www.quartz-scheduler.org/documentation/quartz-2.2.2/tutorials/crontrigger.html#special-characters
Below are cron for three different time for every 2nd Monday, Look into the pattern and make change in time as per your need day
For each second Monday of the month at 00:00 hrs, try below:
0 0 0 ? 1/1 MON#2 *
For each second Monday of the month at 10:30 hrs, try below:
0 30 10 ? 1/1 MON#2 *
For each second Monday of the month at 13:30 hrs, try below:
0 30 13 ? 1/1 MON#2 *
Here you go.
0 0 12 ? 1/1 MON#2 *
minute hour day month dayofweek command
0 0 8-14 * 2 /path/here
This will run a job every second tuesday of the month at midnight.
8-14 limits the occurance of tuesday to the second week in the month.
1-7 first week
8-14 second week
15-21 third week
22-28 forth week
29-31 fifth week

how to create a cron expression for every 2 weeks

Here is a cron expression that I tried: 0 0 0 */14 * ?. It creates the following schedule:
Start Time:
Friday, September 8, 2017 1:25 AM
Next Times:
Friday, September 15, 2017, 12:00 AM
Friday, September 29, 2017, 12:00 AM
Sunday, October 1, 2017, 12:00 AM
Sunday, October 15, 2017, 12:00 AM
Sunday, October 29, 2017, 12:00 AM
This expression is working for every 2 weeks in every month, but my requirement is it has to run for every 2 weeks. I mean after executing September 29th, the next date should be October 13, but it schedules for October 1.
There is no direct cron expression for every 2 weeks. I use the following cron expression, which is similar to 2 weeks, but not exactly for 2 weeks.
cron expression for every 2 weeks on the 1st and the 15th of every month at 1:30 AM:
30 1 1,15 * *
Friday every two weeks:
0 0 * * Fri [ $(expr $(date +%W) \% 2) -eq 1 ] && /path/to/command
Found on:
https://cron.help/every-2-weeks-on-friday
30 7 1-7,14-21 * 1
β€œAt 07:30 on every day-of-month from 1 through 7 and every day-of-month from 14 through 21 and on Monday.”
You need to specify a start day. Otherwise it's will always reset with the 1st day of the month.
So this expression "0 0 0 23/14 OCT ? 2017" is every 2 weeks starting on October 23rd 2017
The crontab manual on my Ubuntu 18 says:
Note: The day of a command's execution can be specified by two fields β€” day of month, and day of week. If both fields are restricted (i.e., aren't *), the command will be run when either field matches the current time. For example,
30 4 1,15 * 5 would cause a command to be run at 4:30 am on the 1st and 15th of each month, plus every Friday. One can, however, achieve the desired result
by adding a test to the command (see the last example in EXAMPLE CRON FILE below).
and the mentioned example is:
# Run on every second Saturday of the month
0 4 8-14 * * test $(date +\%u) -eq 6 && echo "2nd Saturday"

Cron Expression for ignoring 1st Saturday of the year & run on all the Saturdays of the year

Can someone help me in building the cron expression. I've a requirement where I need to run my Job on all the Saturdays at 9:00 AM in a year excluding 1st Saturday of the year.
I had tried with the below expression, but its not working..
0 0 9 ? 1 7#2,7#3,7#4 *, 0 0 9 ? 2-12 SAT *
0 0 9 ? 1 7#2,7#3,7#4 * - It means In the month of January run my job at 9:00 AM on 2nd,3rd,4th Saturdays. But the problem here is it is taking the Last saturday only (i.e. 7#4). In some tutorials I read that comma means it considers all the values but to my surprise it is considering only the last value)
0 0 9 ? 2-12 SAT * - It means from the month of February till December I need to run my job at 9:00 AM.
I need to combine these 2 expressions in such a way it should satisfy my requirement.
Thanks In Advance
You need put compare in your program, not in cronjob. For example, in Unix shell script:
#!/usr/bin/env bash
date=$(date +%a)
month=$(date +%m)
day=$($date +%e)
if [ "$date" = "Sat" -a "$month" = "Jan" -a "$day" -lt 8 ];then
echo "Doesn't run this script at 1st Saturday of the year."
exit
fi
# put rest script
set the cronjob to run it only at 9am on Saturday
0 9 * * 6 YOUR_PROGRAM
Explanation:
%a locale's abbreviated weekday name (e.g., Sun)
%b locale's abbreviated month name (e.g., Jan)
%e day of month, space padded; same as %_d

Cron for job to run on first Sunday of the month

I have a cron line for running a command each first Sunday of the month, which looks like this:
0 19 1-7 * 0 command.sh
Minutes=0
Hours=19
Day= 1st to 7th
* = any month
0 = first day of the week (Sunday)
However, I had the surprise command.sh has run last Sunday (16th of June). Can anyone explain why my cron line is mistaken?
As an alternative, according to a wiki page, it is possible to use the "#" character to: "allow you to specify constructs such as "the second Friday" of a given month" . Is there an example available as how to use this to fit "the first Sunday of a given month"?
try this
0 0 1 ? 1/1 SUN#1 *
it will run at 1 PM every first sunday of month
Your script will run at 19, the first seven days of each month (1-2-3-4-5-6-7) AND every Sunday.
This should works in your case:
0 19 1-7 * Sun [ "$(date '+\%a')" == "Sun" ] && /some/command
Another expression which similar what Haxis mentioned below ,
0 19 1-7 * Sun [ $(date +%d) -le 07 ] && /some/command
This expression:
0 0 19 ? * 1#1 *
It will run on 19:00 on the first Sunday of every month.

Resources