This is a simple script to convert a given unit of time to other units of time. I wrote this mainly to practice writing scripts that incorporate positional parameters. It actually turned out better than I expected. It tests if the number of parameters is correct. It tests if the content of the parameter is valid. Any invalid options triggers a usage help function before exiting.
The script can convert seconds, minutes, hours, days, weeks, months and years. But it attempts to only display conversions that are most applicable or relevant to the information fed to it. For instance converting 600 minutes returns values for the corresponding seconds, hours and days but it does not return any values for weeks, months or years. Those values are filtered out using regular expressions. It supports using numbers with decimals in the input string. Up to 6 decimal places are supported. Any more than 6 and it defaults back to 2.
I'd like to know if there is anything I overlooked. Or maybe other possible arguments I could implement. Converting milliseconds for instance Or perhaps I could implement a setting that doesn't filter results or limit the number of decimals places. Anything I could do better. Redundancies I could remove. Honestly I'd appreciate the harshest most scathing, unforgiving review anyone has to offer. Rip into me please. :)
#!/usr/local/bin/bash
usage() {
echo "You must specify a unit of time; e.g. 60 --minutes"
echo "Examples:"
printf '%b\n' "\t$0 -m 60"
printf '%b\n' "\t$0 39.5 --hours"
exit 1
}
declare ss=
declare mm=
declare hh=
declare dd=
declare ww=
declare nn=
declare yy=
main() {
[[ $# -eq 2 ]] || usage
while [[ "$1" ]]; do
case "$1" in
-s|-second|-seconds|--second|--seconds)
ss=1
;;
-m|-minute|-minutes|--minute|--minutes)
mm=1
;;
-h|-hour|-hours|--hour|--hours)
hh=1
;;
-d|-day|-days|--day|--days)
dd=1
;;
-w|-week|-weeks|--week|--weeks)
ww=1
;;
-t|-month|-months|--month|--months)
nn=1
;;
-y|-year|-years|--year|--years)
yy=1
;;
*)
[[ "$1" =~ ^[0-9]+\.{0,1}[0-9]*$ ]] || usage
int="$1"
## determine number of decimal places
if [[ $int =~ \. ]] ; then
n="${int#*.}";
n="${#n}";
[[ $n -lt 2 ]] && n=2
[[ $n -gt 6 ]] && n=6
else
n=2
fi
;;
esac
shift
done
## values of each unit in seconds
minute=60
hour=3600
day=86400
week=604800
month=2629746
year=31536000
[[ $ss ]] && s="$int"
[[ $mm ]] && s=$(bc -ql <<< "scale=$n; ($int*$minute)");
[[ $hh ]] && s=$(bc -ql <<< "scale=$n; ($int*$hour)");
[[ $dd ]] && s=$(bc -ql <<< "scale=$n; ($int*$day)");
[[ $ww ]] && s=$(bc -ql <<< "scale=$n; ($int*$week)");
[[ $nn ]] && s=$(bc -ql <<< "scale=$n; ($int*$month)");
[[ $yy ]] && s=$(bc -ql <<< "scale=$n; ($int*$year)");
results() {
LC_ALL=en_US.UTF-8
secs=$(printf "%'.${n}f" "$s")
mins=$(printf "%'.${n}f\n" $(bc -ql <<< "scale=$n; ($s/$minute)"));
hours=$(printf "%'.${n}f\n" $(bc -ql <<< "scale=$n; ($s/$hour)"));
days=$(printf "%'.${n}f\n" $(bc -ql <<< "scale=$n; ($s/$day)"));
weeks=$(printf "%'.${n}f\n" $(bc -ql <<< "scale=$n; ($s/$week)"));
months=$(printf "%'.${n}f\n" $(bc -ql <<< "scale=$n; ($s/$month)"));
years=$(printf "%'.${n}f\n" $(bc -ql <<< "scale=$n; ($s/$year)"));
echo "Seconds: $secs"
echo "Minutes: $mins"
echo "Hours: $hours"
echo "Days: $days"
echo "Weeks: $weeks"
echo "Months: $months"
echo "Years: $years"
}
## regular expression to remove values that equal 0
regex='^[A-Z]\w+:\s+0*\.*0$'
while read; do
## strip trailing 0's
if [[ $REPLY =~ [0-9]*\.0+[^1-9]* ]]; then
REPLY=${REPLY%.*}
fi
echo $REPLY
done < <(results) | grep -Ev $regex | column -t
}
main "$@"