Is there a way to get the date of Friday of the current week regardless whether it is in the future or past from current day ?
For example, today is 2021-07-10 so Friday of the current week would be one day ago. But if today was 2021-07-05 Friday of the current week would be four days in the future.
I am aware that with date utility you can get either last Friday or the coming Friday with :
date --date="last Friday" and
date --date="next Friday"
is there a way to get the date of Friday of the current week without complicated logic ?
The only way I know how to do what you want is to do something like the following
date -d "next monday - $(($(date +%u) -1)) days"
Of course, there are side issues such as which day is the start of the business week (it varies), etc.
Here is a simple script to print out a week's dates:
#!/bin/bash
for DAY in monday tuesday wednesday thursday friday saturday sunday
do
# date -d "next $DAY - $(($(date +%u) - 1)) days"
date -d "next $DAY - $(date +%u) days
done
It produces the following output based on today's date:
Mon Jul 5 12:00:00 AM PST 2021
Tue Jul 6 12:00:00 AM PST 2021
Wed Jul 7 12:00:00 AM PST 2021
Thu Jul 8 12:00:00 AM PST 2021
Fri Jul 9 12:00:00 AM PST 2021
Sat Jul 10 12:00:00 AM PST 2021
Sun Jul 11 12:00:00 AM PST 2021
How to set a cron to execute every 10 days starting from 16th January? Would this suffice?
30 7 16-15/10 * * command >/dev/null
The above starts at 7.30 AM, 16th of every month and ends on next month 15th and repeats every 10 days. I don't think what I have above is correct. Can anyone tell me how to set up the cron so that month ends are taken into account and every 10 days the command is executed starting from 16th January this year 2016?.
As William suggested, cron can't handle this complexity by itself. However, you can run a cron job more frequently, and use something else for the logic. For example;
30 7 16-31 1 * date '+\%j' | grep -q '0$' && yourcommand
30 7 * 2-12 * date '+\%j' | grep -q '0$' && yourcommand
This date format string prints the day of the year, from 001 to 365. The grep -q will do a pattern match, NOT print the results, but return a success of a failure on the basis of what it finds. Every 10 days, the day of the year ends in a zero. On those days, yourcommand gets run.
This has a problem with the year roll-over. A more complex alternative might be to do a similar grep on a product of date '+%s' (the epoch second), but you'll need to do math to turn seconds into days for analysis by grep. This might work (you should test):
SHELL=/bin/bash
30 7 * * * echo $(( $(date '+%s') / 86400 )) | grep '0$' && yourcommand
(Add your Jan 16th logic too, of course.)
This relies on the fact that shell arithmetic can only handle integers. The shell simply truncates rather than rounding.
UPDATE
In a comment on another answer, you clarified your requirements:
The command should start executing on January 16th, and continue like on January 26th, February 5th, February 15th and so on – jai
For this, the epoch-second approach is probably the right direction.
% date -v1m -v16d -v7H -v30M -v0S '+%s'
1452947400
(I'm in FreeBSD, hence these arguments to date.)
SHELL=/bin/bash
30 7 * * * [[ $(( ($(date '+\%s') - 1452947400) \% 864000 )) == 0 ]] && yourcommand
This expression subtracts the epoch second of 7:30AM Jan 16 (my timezone) from the current time, and tests whether the resultant difference is divisible by 10 days. If it is, the expression evaluates true and yourcommand is run. Note that $(( 0 % $x )) evaluates to 0 for any value of $x.
This may be prone to error if cron is particularly busy and can't get to your job in the one second where the math works out.
If you want to make this any more complex (and perhaps even if it's this complex), I recommend you move the logic into a separate shell script to handle the date comparison math. Especially if you plan to add a fudge factor to allow for jobs to miss their 1-second window .. that would likely be multiple lines of script, which is awkward to maintain in a single cronjob entry.
Observation: the math capabilities of cron are next to non-existent. The math capabilities of the Unix tools are endless.
Conclusion: move the problem from the cron domain to the shell domain.
Solution: run this each day with 30 7 * * * /path/to/script in the crontab:
#!/bin/sh
PATH=$(/usr/bin/getconf PATH)
if test $(($(date +%j) % 10)) = 6; then
your_command
fi
This tests whether the day-of-year modulo 10 is 6, like it is for January 16 (and January 6th is already in the past...).
Thinking outside the box:
Fix your requirement. Convince whoever came up with that funny 10 day cycle to accept a 7 day cycle. So much easier for cron. This is following the KISS principle.
0 30 7 1/10 * ? * command >/dev/null
Output for the above express is,
Saturday, January 16, 2016 7:30 AM
1. Thursday, January 21, 2016 7:30 AM
2. Sunday, January 31, 2016 7:30 AM
3. Monday, February 1, 2016 7:30 AM
4. Thursday, February 11, 2016 7:30 AM
5. Sunday, February 21, 2016 7:30 AM
Output for your expression
i.e 30 7 16-15/10 * * command >/dev/null
2016-01-15 07:30:00
2016-02-15 07:30:00
2016-03-15 07:30:00
2016-04-15 07:30:00
2016-05-15 07:30:00
2016-06-15 07:30:00
2016-07-15 07:30:00
2016-08-15 07:30:00
2016-09-15 07:30:00
2016-10-15 07:30:00
The closest syntax would like this:
30 7 1-30/10 * *
30 7 1-31/10 * *
30 7 1-28/10 * *
30 7 1-29/10 * *
You can test the cron expression here http://cron.schlitt.info/
In linux bash when I enter date -d "1986-01-01" it shows error
date: invalid date "1986-01-01"
when date -d "1986-01-02" it works
when date -d "1987-01-01" it also works
Why date -d "1986-01-01" shows error in Linux Bash shell.
I am using Fedora 16
Nepal changed its timezone at the beginning of 1986. The following table is copied from the tzdata package:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Kathmandu 5:41:16 - LMT 1920
5:30 - IST 1986
5:45 - NPT # Nepal Time
That means that on Jan 1 1986 the time from 00:00:00 to 00:14:59 is not valid. The following two commands show, that the first day of 1986 started with 00:15:00:
$ TZ=Asia/Kathmandu date -d '1985-12-31 23:59:59' '+%s'
504901799
$ TZ=Asia/Kathmandu date -d '1986-01-01 00:15:00' '+%s'
504901800
So the error message of date is correct. The date is invalid in this timezone. I am not sure what you are doing with the result of this command. However, you can try to use UTC because all dates are valid and unambiguous in UTC:
$ TZ=UTC date -d '1986-01-01'
Wed Jan 1 00:00:00 UTC 1986
I think you are using alphabet "O" in upper case instead of number "0" in the command :)
The command
mydate=$(date -d "90 days 19850101" +%Y%m%d%H%M%S)
yields 19850401000000. But:
mydate=$(date -d "90 days 19830101" +%Y%m%d%H%M%S)
yields 19830401010000.
How is it possible that in year 1983 one hour is added on 1 April (which is a result I don't want), while for the year 1985 the answer is correct?
I am using Ubuntu 10.04 LTS. In bash I am getting error while converting string to date like this:
date -d '20110327 02:00'
date: invalid date `20110327 02:00'
but these work:
date -d '20110327 03:00'
Sun Mar 27 03:00:00 CEST 2011
date -d '20110326 02:00'
Sat Mar 26 02:00:00 CET 2011
date -d '20110328 02:00'
Mon Mar 28 02:00:00 CEST 2011
Any ideas?
Thanks,
Jan
It's the summer time !
In 2011, we get an additionnal hour on the March 27th at 2:00 it was in fact 3:00.
So 27/03/2011 2:00 is not a valid date :-)
Nope, I'm sure there was a transition to/from Daylight Saving Time (DST) at 2:00 that day, so there wasn't 2:00 :)
Well there is no such local time - there was switch to summer time and the clock went from 1:59 to 3:00.