#!/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` date="`which date`" function daysInMonth { case $1 in 1|3|5|7|8|10|12 ) dim=31 ;; # most common value 4|6|9|11 ) dim=30 ;; 2 ) dim=29 ;; # depending on if it's a leap year * ) dim=-1 ;; # unknown month esac } function isleap { # If specified year is a leap year, returns non-zero value for $leapyear leapyear=$($date -d 12/31/$1 +%j | grep 366) } ####################### #### MAIN BLOCK if [ $# -ne 3 ] ; then echo "Usage: $(basename $0) mon day year" echo " with just numerical values (ex: 1 1 2020)" exit 1 fi $date --version > /dev/null 2>&1 # discard error, if any if [ $? -ne 0 ] ; then echo "Sorry, but $(basename $0) can't run without GNU date." >&2 exit 1 fi eval $($date "+thismon=%m;thisday=%d;thisyear=%Y;dayofyear=%j") endmon=$1; endday=$2; endyear=$3 # lots of parameter checks needed... daysInMonth $endmon # sets $dim variable if [ $endday -lt 0 -o $endday -gt $dim ] ; then echo "Invalid: Month #$endmon only has $dim days." >&2 ; exit 1 fi if [ $endmon -eq 2 -a $endday -eq 29 ] ; then isleap $endyear if [ -z "$leapyear" ] ; then echo "Invalid: $endyear wasn't a leapyear, so February only had 28 days." >&2 exit 1 fi fi if [ $endyear -lt $thisyear ] ; then echo "Invalid: $endmon/$endday/$endyear is prior to the current year." >&2 ; exit 1 fi if [ $endyear -eq $thisyear -a $endmon -lt $thismon ] ; then echo "Invalid: $endmon/$endday/$endyear is prior to the current month." >&2 ; exit 1 fi if [ $endyear -eq $thisyear -a $endmon -eq $thismon -a $endday -lt $thisday ] ; then echo "Invalid: $endmon/$endday/$endyear is prior to the current date." >&2 ; exit 1 fi if [ $endyear -eq $thisyear -a $endmon -eq $thismon -a $endday -eq $thisday ] ; then echo "There are zero days between $endmon/$endday/$endyear and today." >&2 ; exit 0 fi ## if we're working with the same year, the calculation's a bit different if [ $endyear -eq $thisyear ] ; then 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 thisdatefmt="$thismon/$thisday/$thisyear" calculate="$($date -d "12/31/$thisyear" +%j) - $($date -d $thisdatefmt +%j)" daysleftinyear=$(( $calculate )) ### DAYS IN INTERVENING YEARS daysbetweenyears=0 tempyear=$(( $thisyear + 1 )) while [ $tempyear -lt $endyear ] ; do daysbetweenyears=$(( $daysbetweenyears + $($date -d "12/31/$tempyear" +%j) )) tempyear=$(( $tempyear + 1 )) done ### DAYS IN END YEAR dayofyear=$($date --date $endmon/$endday/$endyear +%j) # that's easy! ### NOW ADD IT ALL UP totaldays=$(( $daysleftinyear + $daysbetweenyears + $dayofyear )) fi echo "There are $totaldays days until the date $endmon/$endday/$endyear." exit 0