style(unitproc):dateShort: Change VAR_NAMES to varNames
[BK-2020-03.git] / unitproc / bktemp-timeDuration
1 #!/bin/bash
2
3 # Desc: Template to indicate time duration in ISO-8601 format
4
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 $*"; }
8 timeDuration(){
9 # Desc: Given seconds, output ISO-8601 duration string
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 [1:seconds] ([2:precision])
13 # Version: 1.0.3
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 # exit code 0: success
18 # exit code 1: error_input
19 # exit code 2: error_unknown
20 # Example: 'timeDuration 111111 3' yields 'P1DT6H51M'
21 # Depends: date 8 (gnucoreutils), yell,
22 local returnState argSeconds argPrecision remainder precision witherPrecision
23 local fullYears fullMonths fullDays fullHours fullMinutes fullSeconds
24 local displayYears displayMonths displayDays displayHours displayMinutes displaySeconds
25 local hasYears hasMonths hasDays hasHours hasMinutes hasSeconds
26
27 argSeconds="$1"; # read arg1 (seconds)
28 argPrecision="$2"; # read arg2 (precision)
29 precision=2; # set default precision
30
31 # Check that between one and two arguments is supplied
32 if ! { [[ $# -ge 1 ]] && [[ $# -le 2 ]]; }; then
33 yell "ERROR:Invalid number of arguments:$# . Exiting.";
34 returnState="error_input"; fi
35
36 # Check that argSeconds provided
37 if [[ $# -ge 1 ]]; then
38 ## Check that argSeconds is a positive integer
39 if [[ "$argSeconds" =~ ^[[:digit:]]+$ ]]; then
40 :
41 else
42 yell "ERROR:argSeconds not a digit.";
43 returnState="error_input";
44 fi
45 else
46 yell "ERROR:No argument provided. Exiting.";
47 exit 1;
48 fi
49
50 # Consider whether argPrecision was provided
51 if [[ $# -eq 2 ]]; then
52 # Check that argPrecision is a positive integer
53 if [[ "$argPrecision" =~ ^[[:digit:]]+$ ]] && [[ "$argPrecision" -gt 0 ]]; then
54 precision="$argPrecision";
55 else
56 yell "ERROR:argPrecision not a positive integer. (is $argPrecision ). Leaving early.";
57 returnState="error_input";
58 fi;
59 else
60 :
61 fi;
62
63 remainder="$argSeconds" ; # seconds
64 ## Calculate full years Y, update remainder
65 fullYears=$(( remainder / (365*24*60*60) ));
66 remainder=$(( remainder - (fullYears*365*24*60*60) ));
67 ## Calculate full months M, update remainder
68 fullMonths=$(( remainder / (30*24*60*60) ));
69 remainder=$(( remainder - (fullMonths*30*24*60*60) ));
70 ## Calculate full days D, update remainder
71 fullDays=$(( remainder / (24*60*60) ));
72 remainder=$(( remainder - (fullDays*24*60*60) ));
73 ## Calculate full hours H, update remainder
74 fullHours=$(( remainder / (60*60) ));
75 remainder=$(( remainder - (fullHours*60*60) ));
76 ## Calculate full minutes M, update remainder
77 fullMinutes=$(( remainder / (60) ));
78 remainder=$(( remainder - (fullMinutes*60) ));
79 ## Calculate full seconds S, update remainder
80 fullSeconds=$(( remainder / (1) ));
81 remainder=$(( remainder - (remainder*1) ));
82 ## Check which fields filled
83 if [[ $fullYears -gt 0 ]]; then hasYears="true"; else hasYears="false"; fi
84 if [[ $fullMonths -gt 0 ]]; then hasMonths="true"; else hasMonths="false"; fi
85 if [[ $fullDays -gt 0 ]]; then hasDays="true"; else hasDays="false"; fi
86 if [[ $fullHours -gt 0 ]]; then hasHours="true"; else hasHours="false"; fi
87 if [[ $fullMinutes -gt 0 ]]; then hasMinutes="true"; else hasMinutes="false"; fi
88 if [[ $fullSeconds -gt 0 ]]; then hasSeconds="true"; else hasSeconds="false"; fi
89
90 ## Determine which fields to display (see ISO-8601:2004 §4.4.3.2)
91 witherPrecision="false"
92
93 ### Years
94 if $hasYears && [[ $precision -gt 0 ]]; then
95 displayYears="true";
96 witherPrecision="true";
97 else
98 displayYears="false";
99 fi;
100 if $witherPrecision; then ((precision--)); fi;
101
102 ### Months
103 if $hasMonths && [[ $precision -gt 0 ]]; then
104 displayMonths="true";
105 witherPrecision="true";
106 else
107 displayMonths="false";
108 fi;
109 if $witherPrecision && [[ $precision -gt 0 ]]; then
110 displayMonths="true";
111 fi;
112 if $witherPrecision; then ((precision--)); fi;
113
114 ### Days
115 if $hasDays && [[ $precision -gt 0 ]]; then
116 displayDays="true";
117 witherPrecision="true";
118 else
119 displayDays="false";
120 fi;
121 if $witherPrecision && [[ $precision -gt 0 ]]; then
122 displayDays="true";
123 fi;
124 if $witherPrecision; then ((precision--)); fi;
125
126 ### Hours
127 if $hasHours && [[ $precision -gt 0 ]]; then
128 displayHours="true";
129 witherPrecision="true";
130 else
131 displayHours="false";
132 fi;
133 if $witherPrecision && [[ $precision -gt 0 ]]; then
134 displayHours="true";
135 fi;
136 if $witherPrecision; then ((precision--)); fi;
137
138 ### Minutes
139 if $hasMinutes && [[ $precision -gt 0 ]]; then
140 displayMinutes="true";
141 witherPrecision="true";
142 else
143 displayMinutes="false";
144 fi;
145 if $witherPrecision && [[ $precision -gt 0 ]]; then
146 displayMinutes="true";
147 fi;
148 if $witherPrecision; then ((precision--)); fi;
149
150 ### Seconds
151
152 if $hasSeconds && [[ $precision -gt 0 ]]; then
153 displaySeconds="true";
154 witherPrecision="true";
155 else
156 displaySeconds="false";
157 fi;
158 if $witherPrecision && [[ $precision -gt 0 ]]; then
159 displaySeconds="true";
160 fi;
161 if $witherPrecision; then ((precision--)); fi;
162
163 ## Determine whether or not the "T" separator is needed to separate date and time elements
164 if ( $displayHours || $displayMinutes || $displaySeconds); then
165 displayDateTime="true"; else displayDateTime="false"; fi
166
167 ## Construct duration output string
168 OUTPUT="P"
169 if $displayYears; then
170 OUTPUT=$OUTPUT$fullYears"Y"; fi
171 if $displayMonths; then
172 OUTPUT=$OUTPUT$fullMonths"M"; fi
173 if $displayDays; then
174 OUTPUT=$OUTPUT$fullDays"D"; fi
175 if $displayDateTime; then
176 OUTPUT=$OUTPUT"T"; fi
177 if $displayHours; then
178 OUTPUT=$OUTPUT$fullHours"H"; fi
179 if $displayMinutes; then
180 OUTPUT=$OUTPUT$fullMinutes"M"; fi
181 if $displaySeconds; then
182 OUTPUT=$OUTPUT$fullSeconds"S"; fi
183
184 ## Output duration string to stdout
185 echo "$OUTPUT" && returnState="true";
186
187 #===Determine function return code===
188 if [ "$returnState" = "true" ]; then
189 return 0;
190 elif [ "$returnState" = "error_input" ]; then
191 yell "ERROR:input";
192 return 1;
193 else
194 yell "ERROR:Unknown";
195 return 2;
196 fi
197
198 } # Get duration (ex: PT10M4S )
199
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)"
208 timeDuration "$@"
209 #==END sample code==
210
211 # Author: Steven Baltakatei Sandoval
212 # License: GPLv3+