3 # Desc: Template to indicate time duration in ISO-8601 format
5 yell
() { echo "$0: $*" >&2; } # Yell, Die, Try Three-Fingered Claw technique; # Ref/Attrib: https://stackoverflow.com/a/25515370
6 die
() { yell
"$*"; exit 111; }
7 try
() { "$@" || die
"cannot $*"; }
9 # Desc: Output approximate time duration string before given time (default:current date)
10 # Ref/Attrib: ISO-8601:2004(E), §4.4.4.2 Representations of time intervals by duration and context information
11 # Note: "1 month" ("P1M") is assumed to be "30 days" (see ISO-8601:2004(E), §2.2.1.2)
12 # Usage: timeDuration [arg1] ([arg2])
14 # Input: arg1: seconds as base 10 integer >= 0 (ex: 3601)
15 # arg2: precision level (optional; default=2)
16 # Output: stdout: ISO-8601 duration string (ex: "P1H1S", "P2Y10M15DT10H30M20S")
17 # Example: 'timeDuration 111111 3' yields 'P1DT6H51M'
18 # Depends: date 8 (gnucoreutils), yell,
19 local returnState ARG1 ARG2 arg1Valid arg2Valid remainder precision witherPrecision
20 local fullYears fullMonths fullDays fullHours fullMinutes fullSeconds
21 local displayYears displayMonths displayDays displayHours displayMinutes displaySeconds
22 local hasYears hasMonths hasDays hasHours hasMinutes hasSeconds
26 precision
=2; # set default precision
27 returnState
="true"; # set default return state
29 # Check that between one and two arguments is supplied
30 if ! { [[ $# -ge 1 ]] && [[ $# -le 2 ]]; }; then
31 yell
"ERROR:Invalid number of arguments:$# . Exiting.";
32 returnState
="ERROR_INPUT"; fi
34 # Check that arg1 provided
35 if [[ $# -ge 1 ]]; then
36 # Check that arg1 is a positive integer
37 if [[ "$ARG1" =~ ^
[[:digit
:]]+$
]]; then
40 yell
"ERROR:ARG1 not a digit.";
41 returnState
="ERROR_INPUT";
45 yell
"ERROR:No argument provided. Exiting.";
49 # Consider whether arg2 was provided
50 if [[ $# -eq 2 ]]; then
51 # Check that the second arg is a positive integer
52 if [[ "$ARG2" =~ ^
[[:digit
:]]+$
]] && [[ "$ARG2" -gt 0 ]]; then
56 yell
"ERROR:ARG2 not a positive integer. (is $ARG2 ). Leaving early.";
57 returnState
="ERROR_INPUT";
64 remainder
="$ARG1" ; # seconds
65 ## Calculate full years Y, update remainder
66 fullYears
=$
(( remainder
/ (365*24*60*60) ));
67 remainder
=$
(( remainder
- (fullYears
*365*24*60*60) ));
68 ## Calculate full months M, update remainder
69 fullMonths
=$
(( remainder
/ (30*24*60*60) ));
70 remainder
=$
(( remainder
- (fullMonths
*30*24*60*60) ));
71 ## Calculate full days D, update remainder
72 fullDays
=$
(( remainder
/ (24*60*60) ));
73 remainder
=$
(( remainder
- (fullDays
*24*60*60) ));
74 ## Calculate full hours H, update remainder
75 fullHours
=$
(( remainder
/ (60*60) ));
76 remainder
=$
(( remainder
- (fullHours
*60*60) ));
77 ## Calculate full minutes M, update remainder
78 fullMinutes
=$
(( remainder
/ (60) ));
79 remainder
=$
(( remainder
- (fullMinutes
*60) ));
80 ## Calculate full seconds S, update remainder
81 fullSeconds
=$
(( remainder
/ (1) ));
82 remainder
=$
(( remainder
- (remainder
*1) ));
83 ## Check which fields filled
84 if [[ $fullYears -gt 0 ]]; then hasYears
="true"; else hasYears
="false"; fi
85 if [[ $fullMonths -gt 0 ]]; then hasMonths
="true"; else hasMonths
="false"; fi
86 if [[ $fullDays -gt 0 ]]; then hasDays
="true"; else hasDays
="false"; fi
87 if [[ $fullHours -gt 0 ]]; then hasHours
="true"; else hasHours
="false"; fi
88 if [[ $fullMinutes -gt 0 ]]; then hasMinutes
="true"; else hasMinutes
="false"; fi
89 if [[ $fullSeconds -gt 0 ]]; then hasSeconds
="true"; else hasSeconds
="false"; fi
91 ## Determine which fields to display (see ISO-8601:2004 §4.4.3.2)
92 witherPrecision
="false"
95 if $hasYears && [[ $precision -gt 0 ]]; then
97 witherPrecision
="true";
101 if $witherPrecision; then ((precision--
)); fi;
104 if $hasMonths && [[ $precision -gt 0 ]]; then
105 displayMonths
="true";
106 witherPrecision
="true";
108 displayMonths
="false";
110 if $witherPrecision && [[ $precision -gt 0 ]]; then
111 displayMonths
="true";
113 if $witherPrecision; then ((precision--
)); fi;
116 if $hasDays && [[ $precision -gt 0 ]]; then
118 witherPrecision
="true";
122 if $witherPrecision && [[ $precision -gt 0 ]]; then
125 if $witherPrecision; then ((precision--
)); fi;
128 if $hasHours && [[ $precision -gt 0 ]]; then
130 witherPrecision
="true";
132 displayHours
="false";
134 if $witherPrecision && [[ $precision -gt 0 ]]; then
137 if $witherPrecision; then ((precision--
)); fi;
140 if $hasMinutes && [[ $precision -gt 0 ]]; then
141 displayMinutes
="true";
142 witherPrecision
="true";
144 displayMinutes
="false";
146 if $witherPrecision && [[ $precision -gt 0 ]]; then
147 displayMinutes
="true";
149 if $witherPrecision; then ((precision--
)); fi;
153 if $hasSeconds && [[ $precision -gt 0 ]]; then
154 displaySeconds
="true";
155 witherPrecision
="true";
157 displaySeconds
="false";
159 if $witherPrecision && [[ $precision -gt 0 ]]; then
160 displaySeconds
="true";
162 if $witherPrecision; then ((precision--
)); fi;
166 ## Determine whether or not the "T" separator is needed to separate date and time elements
167 if ( $displayHours ||
$displayMinutes ||
$displaySeconds); then
168 displayDateTime
="true"; else displayDateTime
="false"; fi
170 ## Construct duration output string
172 if $displayYears; then
173 OUTPUT
=$OUTPUT$fullYears"Y"; fi
174 if $displayMonths; then
175 OUTPUT
=$OUTPUT$fullMonths"M"; fi
176 if $displayDays; then
177 OUTPUT
=$OUTPUT$fullDays"D"; fi
178 if $displayDateTime; then
179 OUTPUT
=$OUTPUT"T"; fi
180 if $displayHours; then
181 OUTPUT
=$OUTPUT$fullHours"H"; fi
182 if $displayMinutes; then
183 OUTPUT
=$OUTPUT$fullMinutes"M"; fi
184 if $displaySeconds; then
185 OUTPUT
=$OUTPUT$fullSeconds"S"; fi
187 ## Output duration string to stdout
188 if [[ "$returnState" = "true" ]]; then echo "$OUTPUT"; fi
190 #===Determine function return code===
191 if [ "$returnState" = "true" ]; then
194 echo "$returnState" 1>&2;
198 } # Get duration (ex: PT10M4S )
200 #==BEGIN sample code==
201 echo "Precision 6 duration:$(timeDuration "$
(date +%s
)" 6)"
202 echo "Precision 5 duration:$(timeDuration "$
(date +%s
)" 5)"
203 echo "Precision 4 duration:$(timeDuration "$
(date +%s
)" 4)"
204 echo "Precision 3 duration:$(timeDuration "$
(date +%s
)" 3)"
205 echo "Precision 2 duration:$(timeDuration "$
(date +%s
)" 2)"
206 echo "Precision 1 duration:$(timeDuration "$
(date +%s
)" 1)"
207 echo "Precision 6 duration:$(timeDuration $((60+60*60+60*60*24+60*60*24*30+60*60*24*365 - (60+60*60+60*60*24+60*60*24*30) )) 6)"
211 # Author: Steven Baltakatei Sandoval