]> zdv2.bktei.com Git - BK-2020-03.git/blob - user/bkdatev
3ab8c3bf1e47f91e3e67e1307cd716cb95a41e5e
[BK-2020-03.git] / user / bkdatev
1 #!/usr/bin/env bash
2 # Desc: Baltakatei's verbose date command
3 # Usage: bkdatev [args]
4 # Example: bkdatev --date="2001-09-11T09:02:59-04"
5 # Version: 1.0.2
6 # Depends: GNU Coreutils 8.32, Bash 3.2.57
7 # Ref/Attrib: [1] "ISO 8601". Wikipedia. https://en.wikipedia.org/wiki/ISO_8601
8 # [2] "Changing the Locale in Wine" https://stackoverflow.com/a/16428951
9 # [3] "Shanghai vs Beijing" https://bugs.launchpad.net/ubuntu/+source/libgweather/+bug/228554
10 # [4] “Understanding the "right" time zone database” https://kenta.blogspot.com/2016/03/sqfzcxay-understanding-right-time-zone.html
11 # Notes: * Check `ls -R /usr/share/zoneinfo` for time zone names.
12 # * Check `cat /usr/share/i18n/SUPPORTED` for supported locales.
13 # * For list of valid locales, see: https://manpages.ubuntu.com/manpages/bionic/man3/DateTime::Locale::Catalog.3pm.html
14 # * Locations chosen for population, personal signifiance, and spatial coverage.
15 # * For International Atomic Time (TAI), use offsets from UTC provided in `/usr/share/zoneinfo/leap-seconds.list`.
16 # * Compatibility with macOS may be limited if any arguments
17 # are provided when running `bkdatev`; e.g. passing a
18 # `--date` option to `bkdatev` will fail.
19
20 yell() { echo "$0: $*" >&2; }
21 die() { yell "$*"; exit 111; }
22 must() { "$@" || die "cannot $*"; }
23 insertStr() {
24 # Desc: Inserts a string into another string at a specified position.
25 # Input: arg1: str str_rec String to receive insertion
26 # arg2: int pos Insertion position (0 = append to front)
27 # arg3: str str_ins String to be inserted
28 # Output: stdout: Combined string
29 # Version: 0.0.2
30 # Depends: BK-2020-03: yell(), die(), must()
31 # Ref/Attrib: * BK-2020-03: https://gitlab.com/baltakatei/baltakatei-exdev/
32 # * Cooper, Mendel. “Advanced Bash-Scripting Guide: Manipulating Strings”. tldp.org https://tldp.org/LDP/abs/html/string-manipulation.html
33
34 local str_rec pos str_ins re len_str_rec;
35 local pfx_pos_start pfx_len pfx;
36 local sfx_pos_start sfx_len sfx;
37
38 # Check args
39 if [[ $# -ne 3 ]]; then
40 yell "ERROR:Invalid argument count:$#";
41 return 1; fi;
42 re='^[0-9]+$';
43 if [[ ! "$2" =~ $re ]]; then
44 yell "ERROR:Not an int:$2";
45 return 1; fi;
46 str_rec="$1";
47 pos="$2";
48 str_ins="$3";
49
50 # Calculate string stats
51 len_str_rec="${#str_rec}";
52
53 # Form prefix
54 pfx_pos_start="0";
55 pfx_len="$pos";
56 pfx="${str_rec:$pfx_pos_start:$pfx_len}";
57
58 # Form suffix
59 sfx_pos_start="$(( pos ))";
60 sfx_len="$(( len_str_rec - pos ))";
61 sfx="${str_rec:$sfx_pos_start:$sfx_len}";
62
63 # Print output to stdout
64 printf "%s%s%s\n" "$pfx" "$str_ins" "$sfx";
65 }; # Insert string provided at indicated position via stdout
66 line_sep() {
67 # Input: var: n_ln
68 local skip_every=4;
69 ((n_ln++));
70 if ! ((n_ln % "$skip_every")); then
71 printf "\n";
72 fi;
73 return 0;
74 }; # periodically print separating blank line
75 get_tz_offset() {
76 # Desc: Get from 'date' the timezone UTC offset in a way
77 # compatible with both GNU Coreutils and BSD versions.
78 # Input: env var: TZ (time zone for date; e.g. 'America/Denver')
79 # args: $@ # passed onto `date`
80 # Depends: date (GNU Coreutils 8.32 or BSD), rev
81 local ntz ntz ntz_out;
82 local last2;
83
84 # Get numeric time zone string in way compatible with GNU Coreutils and BSD
85 ntz="$(date "+%z" "$@")"; # e.g. "+0530"
86
87 # Check if last two characters are trailing zeros that can be removed.
88 last2="${ntz:3:2}"; # assumes $ntz is 5 characters (i.e. "±HHMM")
89 #last2="$(rev <<< $ntz)" && last2="${last2:0:2}" && last2="$(rev <<< "$last2")";
90 if [[ "$last2" == "00" ]]; then
91 ## ntz_out is truncated by 2 characters
92 len_ntz="${#ntz}";
93 len_ntz_out="$(( len_ntz - 2 ))";
94 ntz_out=""${ntz:0:$len_ntz_out};
95 else
96 ## ntz_out is ntz with semicolon inserted after HH
97 ntz_out="$(insertStr "$ntz" 3 ":" )";
98 fi;
99
100 # Output via stdout
101 printf "%s" "$ntz_out";
102 }; # Format numeric time zone (for BSD date compatibility)
103 print_dateline() {
104 # Input: var: $id
105 # var: $fs_1
106 # var: $fs_2
107 # var: $fs_3
108 # args: $@ # passed on to `date`
109 # env var: TZ (time zone for date; e.g. 'America/Denver')
110 # Output: stdout
111 # Depends: printf, date
112 # get_tz_offset()
113 # Ref/Attrib: * Truncate string in printf https://stackoverflow.com/a/46812677
114 local s_1 s_2 s_2_tz s_3 s_4;
115
116 s_1="$id";
117 s_2="$(date "$@" "$fs_1")"; # ISO-8601 without numeric timezone
118 s_3="$(date "$@" "$fs_2")"; # Alternate ISO-8601 expressions
119 s_4="$(date "$@" "$fs_3")"; # locale-specific date strings
120
121 # Append numeric timezone to $s_2 with appropriate format
122 # (e.g. '-07' for 'Arizona', '+05:45' for 'Asia/Kathmandu')
123 s_2_tz="$(get_tz_offset "$@")";
124 s_2="$( printf "%s%s" "$s_2" "$s_2_tz" )";
125
126 printf "%-10.10s %-25.25s (%-20.20s) (%s)" "$s_1" "$s_2" "$s_3" "$s_4";
127 printf "\n";
128
129 unset fs_1 fs_2 fs_3 fs_4;
130 }; # print line of dates
131 main() {
132 n_ln=0; # for line_sep()
133 unset LC_TIME; # Fall back to time zone-specific locale settings.
134
135 # format strings
136 fs_iso8601="+%Y-%m-%dT%H:%M:%S"; # typical ISO-8601 without timezone
137 fs_iso8601_etc="+%G-W%V-%u, %Y-%j"; # alternate ISO-8601 dates
138 fs_locale="+%Z; %A; %c"; # locale-specific date strings
139
140 # vars for print_dateline()
141 fs_1="$fs_iso8601";
142 fs_2="$fs_iso8601_etc";
143 fs_3="$fs_locale";
144
145 # UTC (pop. (2021): 7,837,000,000)
146 (
147 export TZ=UTC;
148 id="UTC";
149 date_string="$(date -Is)";
150 right_epoch="$(TZ=right/UTC date --date="$date_string" +%s;)"; # see [4]
151 fs_3="+%s seconds (${right_epoch} with leap seconds) since 1970-01-01T00:00+00";
152 print_dateline "$@";
153 ); line_sep;
154
155 # Hawaii
156 (
157 export TZ=US/Hawaii;
158 export LANG="haw-US.UTF8";
159 id="HAWAII";
160 print_dateline "$@";
161 ); line_sep;
162
163 # Los Angeles, USA
164 (
165 export TZ=America/Los_Angeles;
166 export LANG="en_US.UTF-8";
167 id="LOS ANGELES";
168 print_dateline "$@";
169 ); line_sep;
170
171 # Denver, USA (pop. (2021): 711,463)
172 (
173 export TZ=America/Denver;
174 export LANG="en_US.UTF-8";
175 id="DENVER";
176 print_dateline "$@";
177 ); line_sep;
178
179 # Chicago, USA (pop. (2021): 711,463)
180 (
181 export TZ=America/Chicago;
182 export LANG="en_US.UTF-8";
183 id="CHICAGO";
184 print_dateline "$@";
185 ); line_sep;
186
187 # Mexico City, Mexico (pop. (2018): 21,804,515)
188 (
189 export TZ=America/Mexico_City;
190 export LANG="es_MX.UTF8";
191 id="MEXICO CITY";
192 print_dateline "$@";
193 ); line_sep;
194
195 # Panama City, Panama
196 (
197 export TZ=America/Panama;
198 export LANG="es_PA.UTF8";
199 id="PANAMA CITY";
200 print_dateline "$@";
201 ); line_sep;
202
203 # New York, USA (pop. (2018): 20,140,470)
204 (
205 export TZ=America/New_York;
206 export LANG="en_US.UTF-8";
207 id="NEW YORK";
208 print_dateline "$@";
209 ); line_sep;
210
211 # São Paulo, Brazil
212 (
213 export TZ=America/Sao_Paulo;
214 export LANG="pt_BR.UTF8";
215 id="SAO PAULO";
216 print_dateline "$@";
217 ); line_sep;
218
219 # Buenos Aires
220 (
221 export TZ=America/Argentina/Buenos_Aires;
222 export LANG="es_AR.UTF8";
223 id="BUENOS AIRES";
224 print_dateline "$@";
225 ); line_sep;
226
227 # London, England
228 (
229 export TZ=Europe/London;
230 export LANG="en_GB.UTF-8";
231 id="LONDON";
232 print_dateline "$@";
233 ); line_sep;
234
235 # Kinshasa, Africa
236 (
237 export TZ=Africa/Kinshasa;
238 export LANG="ln_CD.UTF8";
239 id="KINSHASA";
240 print_dateline "$@";
241 ); line_sep;
242
243 # Lagos, Africa
244 (
245 export TZ=Africa/Lagos;
246 export LANG="en_NG.UTF8";
247 id="LAGOS";
248 print_dateline "$@";
249 ); line_sep;
250
251 # Paris, France
252 (
253 export TZ=Europe/Paris;
254 export LANG="fr_FR.UTF8";
255 id="PARIS";
256 print_dateline "$@";
257 ); line_sep;
258
259 # Stockholm, Sweden
260 (
261 export TZ=Europe/Stockholm;
262 export LANG="sv_SE.UTF8";
263 id="STOCKHOLM";
264 print_dateline "$@";
265 ); line_sep;
266
267 # Helsinki, Finland
268 (
269 export TZ=Europe/Helsinki;
270 export LANG="fi_FI.UTF8";
271 id="HELSINKI";
272 print_dateline "$@";
273 ); line_sep;
274
275 # Cairo, Egypt
276 (
277 export TZ=Africa/Cairo;
278 export LANG="ar_EG.UTF8";
279 id="CAIRO";
280 print_dateline "$@";
281 ); line_sep;
282
283 # Gaza City, Palestine (pop. (2017): 590,481)
284 (
285 export TZ=Asia/Gaza;
286 export LANG="ar_JO.UTF-8"; # ar_PS is missing as of 2023-10-18, using ar_JO as closest substitute.
287 id="GAZA";
288 print_dateline "$@";
289 ); line_sep;
290
291 # Tel Aviv, Israel (pop. (2021): 467,875)
292 (
293 export TZ=Asia/Tel_Aviv;
294 export LANG="he_IL.UTF-8";
295 id="TEL AVIV";
296 print_dateline "$@";
297 ); line_sep;
298
299 # Athens (pop. (2020): 3,526,887)
300 (
301 export TZ=Europe/Athens;
302 export LANG="el_GR.UTF8";
303 id="ATHENS";
304 print_dateline "$@";
305 ); line_sep;
306
307 # Istanbul (pop. (2020): 13,719,061)
308 (
309 export TZ=Asia/Istanbul;
310 export LANG="tr_TR.UTF8";
311 id="ISTANBUL";
312 print_dateline "$@";
313 ); line_sep;
314
315 # Tehran, Iran
316 (
317 export TZ=Asia/Tehran;
318 export LANG="fa_IR.UTF8";
319 id="TEHRAN";
320 print_dateline "$@";
321 ); line_sep;
322
323 # Moscow, Russia
324 (
325 export TZ=Europe/Moscow;
326 export LANG="ru_RU.UTF-8";
327 id="MOSCOW";
328 print_dateline "$@";
329 ); line_sep;
330
331 # Kyiv, Ukraine (pop. (2021): 2,962,180)
332 (
333 export TZ=Europe/Kyiv;
334 export LANG="uk_UA.UTF-8";
335 id="KYIV";
336 print_dateline "$@";
337 ); line_sep;
338
339 # Delhi, India (pop. (2018): 29,000,000)
340 (
341 export TZ=Asia/Kolkata;
342 export LANG="hi_IN.UTF-8";
343 id="DELHI";
344 print_dateline "$@";
345 ); line_sep;
346
347 # Jakarta, Indonesia (pop. (2018): 33,430,285)
348 (
349 export TZ=Asia/Jakarta;
350 export LANG="id_ID.UTF8";
351 id="JAKARTA";
352 print_dateline "$@";
353 ); line_sep;
354
355 # Singapore, Singapore (pop (2018): 5,792,000)
356 (
357 export TZ=Asia/Singapore;
358 export LANG="en_SG.UTF-8";
359 id="SINGAPORE";
360 print_dateline "$@";
361 ); line_sep;
362
363 # Beijing, China (pop. (2018): 19,618,000)
364 (
365 export TZ=Asia/Shanghai; # [3]
366 export LANG="zh_CN.UTF-8";
367 id="BEIJING";
368 print_dateline "$@";
369 ); line_sep;
370
371 # Taipei, Taiwan (pop (2019): 7,034,084)
372 (
373 export TZ=Asia/Taipei; # [3]
374 export LANG="zh_TW.UTF-8";
375 id="TAIPEI";
376 print_dateline "$@";
377 ); line_sep;
378
379 # Tokyo, Japan (pop. (2018): 37,274,000)
380 (
381 export TZ=Asia/Tokyo;
382 export LANG="ja_JP.UTF8";
383 id="TOKYO";
384 print_dateline "$@";
385 ); line_sep;
386
387 # Seoul, South Korea (pop. (2018): 25,514,000)
388 (
389 export TZ=Asia/Seoul;
390 export LANG="ko_KR.UTF8";
391 id="SEOUL";
392 print_dateline "$@";
393 ); line_sep;
394
395 # Pyongyang, North Korea
396 (
397 export TZ=Asia/Pyongyang;
398 export LANG="ko_KP.UTF8";
399 id="PYONGYANG";
400 print_dateline "$@";
401 ); line_sep;
402
403 # Sydney, Australia
404 (
405 export TZ=Australia/Sydney;
406 export LANG="en_AU.UTF8";
407 id="SYDNEY";
408 print_dateline "$@";
409 ); line_sep;
410
411 # Guam
412 (
413 export TZ=Pacific/Guam;
414 export LANG="en_GU.UTF8";
415 id="GUAM";
416 print_dateline "$@";
417 ); line_sep;
418
419 # Auckland, New Zealand
420 (
421 export TZ=Pacific/Auckland;
422 export LANG="en_NZ.UTF8";
423 id="AUCKLAND";
424 print_dateline "$@";
425 ); line_sep;
426
427 return 0;
428 }; # main program
429
430 main "$@";
431
432 # Author: Steven Baltakatei Sandoval
433 # License: GPLv3+