-
Notifications
You must be signed in to change notification settings - Fork 0
/
101-daysuntil
118 lines (83 loc) · 3.18 KB
/
101-daysuntil
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#!/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