mirror of https://github.com/tLDP/LDP
156 lines
3.8 KiB
Bash
156 lines
3.8 KiB
Bash
#!/bin/bash
|
|
# days-between.sh: Number of days between two dates.
|
|
# Usage: ./days-between.sh [M]M/[D]D/YYYY [M]M/[D]D/YYYY
|
|
#
|
|
# Note: Script modified to account for changes in Bash, v. 2.05b +,
|
|
#+ that closed the loophole permitting large negative
|
|
#+ integer return values.
|
|
|
|
ARGS=2 # Two command-line parameters expected.
|
|
E_PARAM_ERR=85 # Param error.
|
|
|
|
REFYR=1600 # Reference year.
|
|
CENTURY=100
|
|
DIY=365
|
|
ADJ_DIY=367 # Adjusted for leap year + fraction.
|
|
MIY=12
|
|
DIM=31
|
|
LEAPCYCLE=4
|
|
|
|
MAXRETVAL=255 # Largest permissible
|
|
#+ positive return value from a function.
|
|
|
|
diff= # Declare global variable for date difference.
|
|
value= # Declare global variable for absolute value.
|
|
day= # Declare globals for day, month, year.
|
|
month=
|
|
year=
|
|
|
|
|
|
Param_Error () # Command-line parameters wrong.
|
|
{
|
|
echo "Usage: `basename $0` [M]M/[D]D/YYYY [M]M/[D]D/YYYY"
|
|
echo " (date must be after 1/3/1600)"
|
|
exit $E_PARAM_ERR
|
|
}
|
|
|
|
|
|
Parse_Date () # Parse date from command-line params.
|
|
{
|
|
month=${1%%/**}
|
|
dm=${1%/**} # Day and month.
|
|
day=${dm#*/}
|
|
let "year = `basename $1`" # Not a filename, but works just the same.
|
|
}
|
|
|
|
|
|
check_date () # Checks for invalid date(s) passed.
|
|
{
|
|
[ "$day" -gt "$DIM" ] || [ "$month" -gt "$MIY" ] ||
|
|
[ "$year" -lt "$REFYR" ] && Param_Error
|
|
# Exit script on bad value(s).
|
|
# Uses or-list / and-list.
|
|
#
|
|
# Exercise: Implement more rigorous date checking.
|
|
}
|
|
|
|
|
|
strip_leading_zero () # Better to strip possible leading zero(s)
|
|
{ #+ from day and/or month
|
|
return ${1#0} #+ since otherwise Bash will interpret them
|
|
} #+ as octal values (POSIX.2, sect 2.9.2.1).
|
|
|
|
|
|
day_index () # Gauss' Formula:
|
|
{ # Days from March 1, 1600 to date passed as param.
|
|
# ^^^^^^^^^^^^^
|
|
day=$1
|
|
month=$2
|
|
year=$3
|
|
|
|
let "month = $month - 2"
|
|
if [ "$month" -le 0 ]
|
|
then
|
|
let "month += 12"
|
|
let "year -= 1"
|
|
fi
|
|
|
|
let "year -= $REFYR"
|
|
let "indexyr = $year / $CENTURY"
|
|
|
|
|
|
let "Days = $DIY*$year + $year/$LEAPCYCLE - $indexyr \
|
|
+ $indexyr/$LEAPCYCLE + $ADJ_DIY*$month/$MIY + $day - $DIM"
|
|
# For an in-depth explanation of this algorithm, see
|
|
#+ http://weblogs.asp.net/pgreborio/archive/2005/01/06/347968.aspx
|
|
|
|
|
|
echo $Days
|
|
|
|
}
|
|
|
|
|
|
calculate_difference () # Difference between two day indices.
|
|
{
|
|
let "diff = $1 - $2" # Global variable.
|
|
}
|
|
|
|
|
|
abs () # Absolute value
|
|
{ # Uses global "value" variable.
|
|
if [ "$1" -lt 0 ] # If negative
|
|
then #+ then
|
|
let "value = 0 - $1" #+ change sign,
|
|
else #+ else
|
|
let "value = $1" #+ leave it alone.
|
|
fi
|
|
}
|
|
|
|
|
|
|
|
if [ $# -ne "$ARGS" ] # Require two command-line params.
|
|
then
|
|
Param_Error
|
|
fi
|
|
|
|
Parse_Date $1
|
|
check_date $day $month $year # See if valid date.
|
|
|
|
strip_leading_zero $day # Remove any leading zeroes
|
|
day=$? #+ on day and/or month.
|
|
strip_leading_zero $month
|
|
month=$?
|
|
|
|
let "date1 = `day_index $day $month $year`"
|
|
|
|
|
|
Parse_Date $2
|
|
check_date $day $month $year
|
|
|
|
strip_leading_zero $day
|
|
day=$?
|
|
strip_leading_zero $month
|
|
month=$?
|
|
|
|
date2=$(day_index $day $month $year) # Command substitution.
|
|
|
|
|
|
calculate_difference $date1 $date2
|
|
|
|
abs $diff # Make sure it's positive.
|
|
diff=$value
|
|
|
|
echo $diff
|
|
|
|
exit 0
|
|
|
|
# Exercise:
|
|
# --------
|
|
# If given only one command-line parameter, have the script
|
|
#+ use today's date as the second.
|
|
|
|
|
|
# Compare this script with
|
|
#+ the implementation of Gauss' Formula in a C program at
|
|
#+ http://buschencrew.hypermart.net/software/datedif
|