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 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";
44 yell
"ERROR:No argument provided. Exiting.";
48 # Consider whether arg2 was provided
49 if [[ $# -eq 2 ]]; then
50 # Check that the second arg is a positive integer
51 if [[ "$ARG2" =~ ^
[[:digit
:]]+$
]] && [[ "$ARG2" -gt 0 ]]; then
54 yell
"ERROR:ARG2 not a positive integer. (is $ARG2 ). Leaving early.";
55 returnState
="ERROR_INPUT";
61 remainder
="$ARG1" ; # seconds
62 ## Calculate full years Y, update remainder
63 fullYears
=$
(( remainder
/ (365*24*60*60) ));
64 remainder
=$
(( remainder
- (fullYears
*365*24*60*60) ));
65 ## Calculate full months M, update remainder
66 fullMonths
=$
(( remainder
/ (30*24*60*60) ));
67 remainder
=$
(( remainder
- (fullMonths
*30*24*60*60) ));
68 ## Calculate full days D, update remainder
69 fullDays
=$
(( remainder
/ (24*60*60) ));
70 remainder
=$
(( remainder
- (fullDays
*24*60*60) ));
71 ## Calculate full hours H, update remainder
72 fullHours
=$
(( remainder
/ (60*60) ));
73 remainder
=$
(( remainder
- (fullHours
*60*60) ));
74 ## Calculate full minutes M, update remainder
75 fullMinutes
=$
(( remainder
/ (60) ));
76 remainder
=$
(( remainder
- (fullMinutes
*60) ));
77 ## Calculate full seconds S, update remainder
78 fullSeconds
=$
(( remainder
/ (1) ));
79 remainder
=$
(( remainder
- (remainder
*1) ));
80 ## Check which fields filled
81 if [[ $fullYears -gt 0 ]]; then hasYears
="true"; else hasYears
="false"; fi
82 if [[ $fullMonths -gt 0 ]]; then hasMonths
="true"; else hasMonths
="false"; fi
83 if [[ $fullDays -gt 0 ]]; then hasDays
="true"; else hasDays
="false"; fi
84 if [[ $fullHours -gt 0 ]]; then hasHours
="true"; else hasHours
="false"; fi
85 if [[ $fullMinutes -gt 0 ]]; then hasMinutes
="true"; else hasMinutes
="false"; fi
86 if [[ $fullSeconds -gt 0 ]]; then hasSeconds
="true"; else hasSeconds
="false"; fi
88 ## Determine which fields to display (see ISO-8601:2004 §4.4.3.2)
89 witherPrecision
="false"
92 if $hasYears && [[ $precision -gt 0 ]]; then
94 witherPrecision
="true";
98 if $witherPrecision; then ((precision--
)); fi;
101 if $hasMonths && [[ $precision -gt 0 ]]; then
102 displayMonths
="true";
103 witherPrecision
="true";
105 displayMonths
="false";
107 if $witherPrecision && [[ $precision -gt 0 ]]; then
108 displayMonths
="true";
110 if $witherPrecision; then ((precision--
)); fi;
113 if $hasDays && [[ $precision -gt 0 ]]; then
115 witherPrecision
="true";
119 if $witherPrecision && [[ $precision -gt 0 ]]; then
122 if $witherPrecision; then ((precision--
)); fi;
125 if $hasHours && [[ $precision -gt 0 ]]; then
127 witherPrecision
="true";
129 displayHours
="false";
131 if $witherPrecision && [[ $precision -gt 0 ]]; then
134 if $witherPrecision; then ((precision--
)); fi;
137 if $hasMinutes && [[ $precision -gt 0 ]]; then
138 displayMinutes
="true";
139 witherPrecision
="true";
141 displayMinutes
="false";
143 if $witherPrecision && [[ $precision -gt 0 ]]; then
144 displayMinutes
="true";
146 if $witherPrecision; then ((precision--
)); fi;
150 if $hasSeconds && [[ $precision -gt 0 ]]; then
151 displaySeconds
="true";
152 witherPrecision
="true";
154 displaySeconds
="false";
156 if $witherPrecision && [[ $precision -gt 0 ]]; then
157 displaySeconds
="true";
159 if $witherPrecision; then ((precision--
)); fi;
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
167 ## Construct duration output string
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
184 ## Output duration string to stdout
185 if [[ "$returnState" = "true" ]]; then echo "$OUTPUT"; fi
187 #===Determine function return code===
188 if [ "$returnState" = "true" ]; then
191 echo "$returnState" 1>&2;
195 } # Get duration (ex: PT10M4S )
197 #==BEGIN sample code==
198 echo "Precision 6 duration:$(timeDuration "$
(date +%s
)" 6)"
199 echo "Precision 5 duration:$(timeDuration "$
(date +%s
)" 5)"
200 echo "Precision 4 duration:$(timeDuration "$
(date +%s
)" 4)"
201 echo "Precision 3 duration:$(timeDuration "$
(date +%s
)" 3)"
202 echo "Precision 2 duration:$(timeDuration "$
(date +%s
)" 2)"
203 echo "Precision 1 duration:$(timeDuration "$
(date +%s
)" 1)"
204 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 # Author: Steven Baltakatei Sandoval