#!/bin/bash # daysuntil -- Basically this is the daysago script backwards, where the # desired date is set as the current date and the current date is used as # the basis of the daysago calculation. # Like the previous script, use `which gdate` if you are on OS X # If you are on Linux, use `which date` setglobal date = $[which date] proc daysInMonth { match $1 { with 1|3|5|7|8|10|12 setglobal dim = '31' # most common value with 4|6|9|11 setglobal dim = '30' with 2 setglobal dim = '29' # depending on if it's a leap year with * setglobal dim = '-1' # unknown month } } proc isleap { # If specified year is a leap year, returns non-zero value for $leapyear setglobal leapyear = $[$date -d 12/31/$1 +%j | grep 366] } ####################### #### MAIN BLOCK if test $Argc -ne 3 { echo "Usage: $[basename $0] mon day year" echo " with just numerical values (ex: 1 1 2020)" exit 1 } $date --version > /dev/null !2 > !1 # discard error, if any if test $Status -ne 0 { echo "Sorry, but $[basename $0] can't run without GNU date." > !2 exit 1 } eval $[$date "+thismon=%m;thisday=%d;thisyear=%Y;dayofyear=%j] setglobal endmon = $1; setglobal endday = $2; setglobal endyear = $3 # lots of parameter checks needed... daysInMonth $endmon # sets $dim variable if test $endday -lt 0 -o $endday -gt $dim { echo "Invalid: Month #$endmon only has $dim days." > !2 ; exit 1 } if test $endmon -eq 2 -a $endday -eq 29 { isleap $endyear if test -z $leapyear { echo "Invalid: $endyear wasn't a leapyear, so February only had 28 days." > !2 exit 1 } } if test $endyear -lt $thisyear { echo "Invalid: $endmon/$endday/$endyear is prior to the current year." > !2 ; exit 1 } if test $endyear -eq $thisyear -a $endmon -lt $thismon { echo "Invalid: $endmon/$endday/$endyear is prior to the current month." > !2 ; exit 1 } if test $endyear -eq $thisyear -a $endmon -eq $thismon -a $endday -lt $thisday { echo "Invalid: $endmon/$endday/$endyear is prior to the current date." > !2 ; exit 1 } if test $endyear -eq $thisyear -a $endmon -eq $thismon -a $endday -eq $thisday { echo "There are zero days between $endmon/$endday/$endyear and today." > !2 ; exit 0 } ## if we're working with the same year, the calculation's a bit different if test $endyear -eq $thisyear { setglobal totaldays = $shExpr(' $($date -d "$endmon/$endday/$endyear" +%j) - $($date +%j) ') } else { ## calculate this in chunks: starting with days left in this year ### DAYS LEFT IN START YEAR # calculate the date string format for the specified starting date setglobal thisdatefmt = ""$thismon/$thisday/$thisyear"" setglobal calculate = ""$[$date -d "12/31/$thisyear" +%j] - $[$date -d $thisdatefmt +%j]"" setglobal daysleftinyear = $shExpr(' $calculate ') ### DAYS IN INTERVENING YEARS setglobal daysbetweenyears = '0' setglobal tempyear = $shExpr(' $thisyear + 1 ') while test $tempyear -lt $endyear { setglobal daysbetweenyears = $shExpr(' $daysbetweenyears + $($date -d "12/31/$tempyear" +%j) ') setglobal tempyear = $shExpr(' $tempyear + 1 ') } ### DAYS IN END YEAR setglobal dayofyear = $[$date --date $endmon/$endday/$endyear +%j] # that's easy! ### NOW ADD IT ALL UP setglobal totaldays = $shExpr(' $daysleftinyear + $daysbetweenyears + $dayofyear ') } echo "There are $totaldays days until the date $endmon/$endday/$endyear." exit 0