number of days remaining in the year in bash - bash

This kills my linter in vs-code.
Is there a one-liner that could better perform this?
echo -n "$((($(date -j -f "%Y%m%d" "$(( $(date +"%Y0101")+10000 ))" "+%s") - $(date "+%s"))/(60*60*24)))";
echo " days until $(( $(date +"%Y")+1 ))"
prints:
308 days until 2020

I would use python:
python -c 'from datetime import datetime as dt;y=dt.now().year+1;print('{} days until {}'.format((dt(y,1,1)-dt.now()).days,y))'
which is the one-linerized version of:
from datetime import datetime as dt
next_year = dt.now().year + 1;
days = (dt(next_year, 1, 1) - dt.now()).days
print('{} days until {}'.format(days, next_year))
Output (using the UTC timezone):
306 days until 2020

Pure Bash one-liner (tested on Linux, no Mac here)
eoy=$([ -n "$(date -d 'Feb 29' '+%-j' 2>/dev/null)" ] && echo 366); echo "$((${eoy:-365} - $(date '+%-j'))) days until $(($(date -d 'Dec 31' '+%Y') +1))"
Result:
307 days until 2020
Testing a leap year:
eoy=$([ -z "$(date -d 'Feb 29 2020' '+%-j' 2>/dev/null)" ] && echo 366); echo "$((${eoy:-365} - $(date '+%-j'))) days until $(($(date -d 'Dec 31 2020' '+%Y') +1))"
Result:
308 days until 2021
Same in 2 lines:
# year days if leap year
eoy=$([ -z "$(date -d 'Feb 29' '+%-j' 2>/dev/null)" ] && echo 366)
# ${eoy:-365} -> if $eoy is not set or empty string use default 365
echo "$((${eoy:-365} - $(date '+%-j'))) days until $(($(date -d 'Dec 31' '+%Y') +1))"

Related

Check if date older than 60 days

Let's say I have a date in this format: 2021-01-26
How would I check to see if this date is 60 days old?
Something like this?
if ($date -gt 60)
then
echo "Date is older than 60 days"
fi
Use the date command to create the date 60 days ago, and compare with that.
sixty_days_ago=$(date +%F -d '60 days ago')
if [[ $date < $sixty_days_ago ]]
then echo "Date is older than 60 days"
fi

bash automate the user input <enter> in the loop

#!/bin/sh
dom=$(date '+%d') # 01-31, day of month
year=$(date '+%Y') # four-digit year
month=$(date '+%m') # two-digit month
nworkdays=0
for d in $( seq 1 $dom)
do
today=$(date -d "$year-$month-$d" '+%x') # locale's date representation (e.g. 12/31/99)
dow=$(date -d "$year-$month-$d" '+%u') # day of week: 1-7 with 1=Monday, 7=Sunday
if [ "$dow" -le 5 ] && grep -vq "$today"
then
workday=Yes
nworkdays=$((nworkdays+1))
else
workday=
fi
done
[ "$workday" ] && [ "$nworkdays" -eq 6 ] && echo "$nworkdays $today $workday"
~
I wanted to execute the script but the script goes inside the loop and asks for user input.
Expected result
on execution display workday
Best Regards,
Shalini
As mentioned by #urbanespacemen kindly remove the grep command
#!/bin/sh
dom=$(date '+%d') # 01-31, day of month
year=$(date '+%Y') # four-digit year
month=$(date '+%m') # two-digit month
nworkdays=0
for d in $( seq 1 $dom)
do
today=$(date -d "$year-$month-$d" '+%x') # locale's date representation (e.g. 12/31/99)
dow=$(date -d "$year-$month-$d" '+%u') # day of week: 1-7 with 1=Monday, 7=Sunday
if [ "$dow" -le 5 ]
then
workday=Yes
nworkdays=$((nworkdays+1))
else
workday=
fi
done
[ "$workday" ] && [ "$nworkdays" -eq 6 ] && echo "$nworkdays $today $workday"
Now should work

bash if statement with time

I am trying to test a date ...if it's between those 2 time frames i want to print them...
But i get errors..This is my script
today_time=$(date +%H:%M:%S --date '-1 sec')
today_dow=$(date +"%u")
today_less=$(date +%H:%M:%S --date '-1 min')
today_more=$(date +%H:%M:%S --date '+1 min')
echo $today_less
echo $today_time
echo $today_more
if [ $today_less -gt $today_time ] && [ $today_time -lt $today_more ]; then
echo "$today_less"
echo "$today_time"
echo "$today_more"
else
echo no
fi
I have tried -ge with -le and gives me: Integer expression expected
-gt and -lt: Integer expression expected
I also used '<' and '>' and gives me: No such file or directory.
I need to make this work with time dates only...not with int
Cause the time i will extract it from the db and replace today_time with the time from db.
Your output is not the digits, but strings like:
[sahaquiel#sahaquiel-PC ~]$ date +%H:%M:%S --date '-1 min'
13:40:30
Convert it to Unixtime and compare clear numbers, for example:
today_time=$(date +%H:%M:%S --date '-1 sec')
today_time_u=$(date +%s --date '-1 sec')
today_dow=$(date +"%u")
today_less=$(date +%H:%M:%S --date '-1 min')
today_less_u=$(date +%s --date '-1 min')
today_more=$(date +%H:%M:%S --date '+1 min')
today_more_u=$(date +%s --date '+1 min')
echo $today_less
echo $today_time
echo $today_more
if [ $today_less_u -gt $today_time_u -a $today_time_u -lt $today_more_u ]; then
echo "$today_less"
echo "$today_time"
echo "$today_more"
else
echo no
fi
And once more, in your example, $today_less is current date - 1 minute; $today_time is current date - 1 second; So, $today_time > $today_less every time and your if [ $today_less_u -gt $today_time_u part will be false every time, so you will not be able get anything but echo no in else statement.

How to list date of every monday and thrusdays in shell scripting?

If I give month and year as input the output should be dates of mondays and thrusdays of that month.
eg: If input is
year = 2013
month = 02
output should be
2013-02-04
2013-02-07
2013-02-11
2013-02-14
2013-02-18
2013-02-21
2013-02-25
2013-02-28
how to use date function for this in shell scripting?
This method requires only 2 call to date, the rest is just arithmetic
year=2013
month=2
last=$(date -d "$year-$month-1 + 1 month - 1 day" +%d)
wday=$(date -d "$year-$month-1" +%w)
for (( day=1; day<=$last; day++ )); do
if (( wday == 1 || wday == 4 )); then
printf "%4d-%02d-%02d\n" $year $month $day
fi
(( wday = (wday + 1) % 7 ))
done
2013-02-04
2013-02-07
2013-02-11
2013-02-14
2013-02-18
2013-02-21
2013-02-25
2013-02-28
year=2013
month=02
#Monday=1,Sunday=7
display_days="1 4"
for day in $(seq 1 31)
do
dow=$(date -d "$year-$month-$day" +%u 2>/dev/null)
for d in $display_days
do
if [ -z $dow ]; then continue; fi
if [ "$dow" -eq "$d" ]
then
date -d "$year-$month-$day" +%y-%m-%d
fi
done
done
Or just defer to ncal.
LC_ALL=C ncal "$#" | sed -n 's/\(Mo\|Th\)//p'
Weekdays are subject to localization so I added a C locale just in case.
Another way:
year=2013 month=02
cal $month $year |
sed '1,2d; s/^.. \(..\) .. .. \(..\).*/\1\n\2/' |
sed "/^ *$/d; s/^ /0/; s/^/$year-$month-/"

bash shell script for yesterdays date (last working day)

I am writing a bash script that needs to print the date of the last working day. So for example if the script is run on a Monday, it will print the date for last Friday.
I found that this prints yesterdays date:
date -d '1 day ago' +'%Y/%m/%d'
I also know that I can get the day of the week by using this statement
date +%w
I want to combine these two statements in order to have a little helper script that prints the required date. The logic goes something like this (note: its Pseudo code - I've never written a bash script)
DAY_OF_WEEK = `date +%w`
if (%DAY_OF_WEEK == 1)
LOOK_BACK = 3
elif
LOOK_BACK = 1
fi
echo `date -d '%LOOK_BACK day ago' +'%Y/%m/%d'`
Can someone help by correcting the pseudo code above?
(I am running on Ubuntu 10.0.4)
You were so close:
day_or_week=`date +%w`
if [ $day_or_week == 1 ] ; then
look_back=3
else
look_back=1
fi
date -d "$look_back day ago" +'%Y/%m/%d'
Sunday also needs to be checked.
DAY_OF_WEEK=`date +%w`
if [ $DAY_OF_WEEK = 0 ] ; then
LOOK_BACK=2
elif [ $DAY_OF_WEEK = 1 ] ; then
LOOK_BACK=3
else
LOOK_BACK=1
fi
date -d "$LOOK_BACK day ago" +'%Y/%m/%d'
I'm using a Mac, so my date command doesn't have the same -d flag yours seems to, but the following should work if it behaves as you've indicated:
if [[ $(date +%w) == 1 ]]
then
LOOK_BACK=3
else
LOOK_BACK=1
fi
date -d "${LOOK_BACK} day ago" +%Y/%m/%d
For OSX (tested on 10.9.2 and 10.13.4), so probably any environment where you are using BSD date.
if [ $(date +%w) == 1 ] ; then
date -v-3d +'%Y/%m/%d'
else
date -v-1d +'%Y/%m/%d'
fi
You can check to see if you are using BSD date by
$ man date | grep "BSD General"
Putting the other answers together, I came up with this:
last_workday() {
from_date="${#:-today}"
day_of_week=$(date +%w --date="${from_date}")
if [ ${day_of_week} = "0" ] ; then
look_back=2
elif [ ${day_of_week} = "1" ] ; then
look_back=3
else
look_back=1
fi
date -d "${from_date} - ${look_back} day" +'%Y/%m/%d'
}
next_workday() {
from_date="${#:-today}"
day_of_week=$(date +%w --date="${from_date}")
if [ ${day_of_week} = "5" ] ; then
look_forward=3
elif [ ${day_of_week} = "6" ] ; then
look_forward=2
else
look_back=1
fi
date -d "${from_date} + ${look_forward} day" +'%Y/%m/%d'
}
for i in $(seq 16); do
now=$(date +'%Y/%m/%d' --date="today + ${i} day")
prev=$(last_workday "${now}")
next=$(next_workday "${now}")
echo "${now}: ${prev} ${next}"
done
A more concise form using a bash inline "ternary" expression:
[[ $(date +%w) == 1 ]] && days=3 || days=1
date -d "$days day ago" +"%Y-%m-%d"

Resources