-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathagainHelpers.sh
158 lines (145 loc) · 4.92 KB
/
againHelpers.sh
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/env bash
#Copyright (C) 2013 Niklas Thorne.
#
#This file is part of again.
#
#again is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#again is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with again. If not, see <http://www.gnu.org/licenses/>.
readonly DATE_FORMAT="%F" # %F == %Y-%m-%d for BSD and GNU
# Set $TODAY to today's date
function today()
{
if [[ $DATE_VERSION == "BSD" || $DATE_VERSION == "GNU" ]]
then
TODAY=`date +$DATE_FORMAT`
else
error "Unknown date implementation. Bailing out."
fi
}
# Adjust $ORIGINAL by $ADJUST, store in $NEW_DATE
function adjust_date()
{
ADJUST_NUM=`expr "$ADJUST" : '+*\([1-9][0-9]*\)'`
ADJUST_UNIT=`expr "$ADJUST" : '.*\([dwmyb]\)'`
if [ -z $ADJUST_UNIT ]
then
ADJUST_UNIT=d
fi
case $ADJUST_UNIT in
b)
if [ $DATE_VERSION == "BSD" ]
then
START_DOW=`date -j -f $DATE_FORMAT $ORIGINAL +%u`
elif [ $DATE_VERSION == "GNU" ]
then
START_DOW=`date -d "$ORIGINAL" +%u`
fi
# To calculate weekdays we determine how many extra days to add for weekends
# If the starting day is Saturday or Sunday save a correction factor
FINAL_DOW_ADJ=$(( $START_DOW > 5 ? $START_DOW % 5 : 0 ))
# If it's the original date isn't a weekday start from the previous weekday (Friday)
START_DOW=$(( $START_DOW > 5 ? 5 : $START_DOW ))
# Calculate how many weekends to include and add 2 days for each
WEEKS=$(( ($START_DOW + $ADJUST_NUM - 1) / 5 ))
ADJUST_NUM=$(( 2 * $WEEKS + $ADJUST_NUM ))
# Subtract the correction for Saturday and Sunday if there is one
ADJUST_NUM=$(( $ADJUST_NUM - $FINAL_DOW_ADJ ))
ADJUST_UNIT=d
;;
*)
esac
if [ $DATE_VERSION == "GNU" ]
then
case $ADJUST_UNIT in
d)
_GNU_UNIT=days
;;
w)
_GNU_UNIT=weeks
;;
m)
_GNU_UNIT=months
;;
y)
_GNU_UNIT=years
;;
*)
esac
# GNU date handles month and year addition in a way that could cause
# todo.txt again users to miss deadlines near the end of the month.
# $ date --version
# date (GNU coreutils) 6.10
# $ date -d "2015-01-31 1 month" +%F
# 2015-03-03 -- Yikes! Task probably due on 2015-02-28
# $ date -d "2016-02-29 2 years" +%F
# 2018-03-01 -- Yikes! Task probably due on 2018-02-28
# We'll work around this problem with some additional logic.
if [ $_GNU_UNIT == "days" ] || [ $_GNU_UNIT == "weeks" ] || [ ${ORIGINAL:8:2} -le "28" ]
then
# No workaround if users are adjusting by days OR the day of the month
# isn't in the danger zone.
NEW_DATE=`date -d "$ORIGINAL $ADJUST_NUM $_GNU_UNIT" +$DATE_FORMAT`
else
_ORIGINAL_MONTH_DAY_ONE=${ORIGINAL:0:8}01
_NEW_MONTH_DAY_ONE=`date -d "$_ORIGINAL_MONTH_DAY_ONE $ADJUST_NUM $_GNU_UNIT" +$DATE_FORMAT`
_NEW_MONTH_LAST_DAY=`date -d "$_NEW_MONTH_DAY_ONE 1 month - 1 day" +$DATE_FORMAT`
if [ ${ORIGINAL:8:2} -lt ${_NEW_MONTH_LAST_DAY:8:2} ]
then
NEW_DATE=${_NEW_MONTH_DAY_ONE:0:8}${ORIGINAL:8:2}
else
NEW_DATE=${_NEW_MONTH_DAY_ONE:0:8}${_NEW_MONTH_LAST_DAY:8:2}
fi
fi
elif [ $DATE_VERSION == "BSD" ]
then
# BSD date handles month and year addition near the end of the month
# better than GNU, but still not quite perfectly.
# $ man date | tail -n 1
# FreeBSD 10.2 May 7, 2015 FreeBSD 10.2
# $ date -j -v+1y -f %F 2016-02-29 +%F
# 2017-03-01 -- Yikes! Task probably due on 2017-02-28
# $ date -j -v-1m -v+1y -v+1m -f %F 2016-02-29 +%F
# 2017-02-28 -- That's more like it
# So for BSD, we'll treat year adjustments carefully.
if [ $ADJUST_UNIT != "y" ]
then
NEW_DATE=`date -j -v+${ADJUST_NUM}${ADJUST_UNIT} -f $DATE_FORMAT $ORIGINAL +$DATE_FORMAT`
else
NEW_DATE=`date -j -v-1m -v+${ADJUST_NUM}${ADJUST_UNIT} -v+1m -f $DATE_FORMAT $ORIGINAL +$DATE_FORMAT`
fi
else
error "Unknown date implementation. Bailing out."
fi
}
# Determine which date implementation is installed on this machine
function determine_date_version()
{
date -v 1d 1>/dev/null 2>/dev/null
# BSD flavor accepts the -v (value) option without complaint
if [ 0 -eq $? ]
then
DATE_VERSION="BSD"
# GNU flavor says so in the --version output
elif [[ $(date --version) =~ GNU ]]
then
DATE_VERSION="GNU"
# else not supported
else
error "Unknown date implementation. Bailing out."
fi
}
function error()
{
echo "error: $@" >&2
exit 1
}