#!/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` setvar date = "$(which date)" proc daysInMonth { case (1) { 1|3|5|7|8|10|12 { setvar dim = '31' } # most common value 4|6|9|11 { setvar dim = '30' } 2 { setvar dim = '29' } # depending on if it's a leap year * { setvar dim = '-1' } # unknown month } } proc isleap { # If specified year is a leap year, returns non-zero value for $leapyear setvar 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 $? -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") setvar endmon = "$1"; setvar endday = "$2"; setvar 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 { setvar totaldays = $(( $($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 setvar thisdatefmt = ""$thismon/$thisday/$thisyear"" setvar calculate = ""$($date -d "12/31/$thisyear" +%j) - $($date -d $thisdatefmt +%j)"" setvar daysleftinyear = $(( $calculate )) ### DAYS IN INTERVENING YEARS setvar daysbetweenyears = '0' setvar tempyear = $(( $thisyear + 1 )) while test $tempyear -lt $endyear { setvar daysbetweenyears = $(( $daysbetweenyears + $($date -d "12/31/$tempyear" +%j) )) setvar tempyear = $(( $tempyear + 1 )) } ### DAYS IN END YEAR setvar dayofyear = $($date --date $endmon/$endday/$endyear +%j) # that's easy! ### NOW ADD IT ALL UP setvar totaldays = $(( $daysleftinyear + $daysbetweenyears + $dayofyear )) } echo "There are $totaldays days until the date $endmon/$endday/$endyear." exit 0