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: 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])
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 # Example: 'timeDuration 111111 3' yields 'P1DT6H51M'
20 # Depends: date 8 (gnucoreutils), yell,
21 local returnState argSeconds argPrecision remainder precision witherPrecision
22 local fullYears fullMonths fullDays fullHours fullMinutes fullSeconds
23 local displayYears displayMonths displayDays displayHours displayMinutes displaySeconds
24 local hasYears hasMonths hasDays hasHours hasMinutes hasSeconds
26 argSeconds
="$1"; # read arg1 (seconds)
27 argPrecision
="$2"; # read arg2 (precision)
28 precision
=2; # set default precision
30 # Check that between one and two arguments is supplied
31 if ! { [[ $# -ge 1 ]] && [[ $# -le 2 ]]; }; then
32 yell
"ERROR:Invalid number of arguments:$# . Exiting.";
33 returnState
="error_input"; fi
35 # Check that argSeconds provided
36 if [[ $# -ge 1 ]]; then
37 ## Check that argSeconds is a positive integer
38 if [[ "$argSeconds" =~ ^
[[:digit
:]]+$
]]; then
41 yell
"ERROR:argSeconds not a digit.";
42 returnState
="error_input";
45 yell
"ERROR:No argument provided. Exiting.";
49 # Consider whether argPrecision was provided
50 if [[ $# -eq 2 ]]; then
51 # Check that argPrecision is a positive integer
52 if [[ "$argPrecision" =~ ^
[[:digit
:]]+$
]] && [[ "$argPrecision" -gt 0 ]]; then
53 precision
="$argPrecision";
55 yell
"ERROR:argPrecision not a positive integer. (is $argPrecision ). Leaving early.";
56 returnState
="error_input";
62 remainder
="$argSeconds" ; # seconds
63 ## Calculate full years Y, update remainder
64 fullYears
=$
(( remainder
/ (365*24*60*60) ));
65 remainder
=$
(( remainder
- (fullYears
*365*24*60*60) ));
66 ## Calculate full months M, update remainder
67 fullMonths
=$
(( remainder
/ (30*24*60*60) ));
68 remainder
=$
(( remainder
- (fullMonths
*30*24*60*60) ));
69 ## Calculate full days D, update remainder
70 fullDays
=$
(( remainder
/ (24*60*60) ));
71 remainder
=$
(( remainder
- (fullDays
*24*60*60) ));
72 ## Calculate full hours H, update remainder
73 fullHours
=$
(( remainder
/ (60*60) ));
74 remainder
=$
(( remainder
- (fullHours
*60*60) ));
75 ## Calculate full minutes M, update remainder
76 fullMinutes
=$
(( remainder
/ (60) ));
77 remainder
=$
(( remainder
- (fullMinutes
*60) ));
78 ## Calculate full seconds S, update remainder
79 fullSeconds
=$
(( remainder
/ (1) ));
80 remainder
=$
(( remainder
- (remainder
*1) ));
81 ## Check which fields filled
82 if [[ $fullYears -gt 0 ]]; then hasYears
="true"; else hasYears
="false"; fi
83 if [[ $fullMonths -gt 0 ]]; then hasMonths
="true"; else hasMonths
="false"; fi
84 if [[ $fullDays -gt 0 ]]; then hasDays
="true"; else hasDays
="false"; fi
85 if [[ $fullHours -gt 0 ]]; then hasHours
="true"; else hasHours
="false"; fi
86 if [[ $fullMinutes -gt 0 ]]; then hasMinutes
="true"; else hasMinutes
="false"; fi
87 if [[ $fullSeconds -gt 0 ]]; then hasSeconds
="true"; else hasSeconds
="false"; fi
89 ## Determine which fields to display (see ISO-8601:2004 §4.4.3.2)
90 witherPrecision
="false"
93 if $hasYears && [[ $precision -gt 0 ]]; then
95 witherPrecision
="true";
99 if $witherPrecision; then ((precision--
)); fi;
102 if $hasMonths && [[ $precision -gt 0 ]]; then
103 displayMonths
="true";
104 witherPrecision
="true";
106 displayMonths
="false";
108 if $witherPrecision && [[ $precision -gt 0 ]]; then
109 displayMonths
="true";
111 if $witherPrecision; then ((precision--
)); fi;
114 if $hasDays && [[ $precision -gt 0 ]]; then
116 witherPrecision
="true";
120 if $witherPrecision && [[ $precision -gt 0 ]]; then
123 if $witherPrecision; then ((precision--
)); fi;
126 if $hasHours && [[ $precision -gt 0 ]]; then
128 witherPrecision
="true";
130 displayHours
="false";
132 if $witherPrecision && [[ $precision -gt 0 ]]; then
135 if $witherPrecision; then ((precision--
)); fi;
138 if $hasMinutes && [[ $precision -gt 0 ]]; then
139 displayMinutes
="true";
140 witherPrecision
="true";
142 displayMinutes
="false";
144 if $witherPrecision && [[ $precision -gt 0 ]]; then
145 displayMinutes
="true";
147 if $witherPrecision; then ((precision--
)); fi;
151 if $hasSeconds && [[ $precision -gt 0 ]]; then
152 displaySeconds
="true";
153 witherPrecision
="true";
155 displaySeconds
="false";
157 if $witherPrecision && [[ $precision -gt 0 ]]; then
158 displaySeconds
="true";
160 if $witherPrecision; then ((precision--
)); fi;
162 ## Determine whether or not the "T" separator is needed to separate date and time elements
163 if ( $displayHours ||
$displayMinutes ||
$displaySeconds); then
164 displayDateTime
="true"; else displayDateTime
="false"; fi
166 ## Construct duration output string
168 if $displayYears; then
169 OUTPUT
=$OUTPUT$fullYears"Y"; fi
170 if $displayMonths; then
171 OUTPUT
=$OUTPUT$fullMonths"M"; fi
172 if $displayDays; then
173 OUTPUT
=$OUTPUT$fullDays"D"; fi
174 if $displayDateTime; then
175 OUTPUT
=$OUTPUT"T"; fi
176 if $displayHours; then
177 OUTPUT
=$OUTPUT$fullHours"H"; fi
178 if $displayMinutes; then
179 OUTPUT
=$OUTPUT$fullMinutes"M"; fi
180 if $displaySeconds; then
181 OUTPUT
=$OUTPUT$fullSeconds"S"; fi
183 ## Output duration string to stdout
184 echo "$OUTPUT" && returnState
="true";
186 #===Determine function return code===
187 if [ "$returnState" = "true" ]; then
189 elif [ "$returnState" = "error_input" ]; then
193 yell
"ERROR:Unknown";
197 } # Get duration (ex: PT10M4S )
199 #==BEGIN sample code==
200 echo "Precision 6 duration:$(timeDuration "$
(date +%s
)" 6)"
201 echo "Precision 5 duration:$(timeDuration "$
(date +%s
)" 5)"
202 echo "Precision 4 duration:$(timeDuration "$
(date +%s
)" 4)"
203 echo "Precision 3 duration:$(timeDuration "$
(date +%s
)" 3)"
204 echo "Precision 2 duration:$(timeDuration "$
(date +%s
)" 2)"
205 echo "Precision 1 duration:$(timeDuration "$
(date +%s
)" 1)"
206 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)"
210 # Author: Steven Baltakatei Sandoval