2 # Desc: Baltakatei's verbose date command 
   3 # Usage: bkdatev [args] 
   4 # Example: bkdatev --date="2001-09-11T09:02:59-04" 
   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 # Notes:  * Check `ls -R /usr/share/zoneinfo` for time zone names. 
  11 #         * Check `cat /usr/share/i18n/SUPPORTED` for supported locales. 
  12 #         * For list of valid locales, see: https://manpages.ubuntu.com/manpages/bionic/man3/DateTime::Locale::Catalog.3pm.html 
  13 #         * Locations chosen for population, personal signifiance, and spatial coverage. 
  14 #         * For International Atomic Time (TAI), use offsets from UTC provided in `/usr/share/zoneinfo/leap-seconds.list`. 
  15 #         * Compatibility with macOS may be limited if any arguments 
  16 #             are provided when running `bkdatev`; e.g. passing a 
  17 #             `--date` option to `bkdatev` will fail. 
  19 yell
() { echo "$0: $*" >&2; } 
  20 die
() { yell 
"$*"; exit 111; } 
  21 must
() { "$@" || die 
"cannot $*"; } 
  23     # Desc: Inserts a string into another string at a specified position. 
  24     # Input: arg1: str   str_rec  String to receive insertion 
  25     #        arg2: int   pos      Insertion position (0 = append to front) 
  26     #        arg3: str   str_ins  String to be inserted 
  27     # Output: stdout:    Combined string 
  29     # Depends: BK-2020-03: yell(), die(), must() 
  30     # Ref/Attrib: * BK-2020-03: https://gitlab.com/baltakatei/baltakatei-exdev/ 
  31     #             * Cooper, Mendel. “Advanced Bash-Scripting Guide: Manipulating Strings”. tldp.org https://tldp.org/LDP/abs/html/string-manipulation.html 
  33     local str_rec pos str_ins re len_str_rec
; 
  34     local pfx_pos_start pfx_len pfx
; 
  35     local sfx_pos_start sfx_len sfx
; 
  38     if [[ $# -ne 3 ]]; then 
  39         yell 
"ERROR:Invalid argument count:$#"; 
  42     if [[ ! "$2" =~ 
$re ]]; then 
  43         yell 
"ERROR:Not an int:$2"; 
  49     # Calculate string stats 
  50     len_str_rec
="${#str_rec}"; 
  55     pfx
="${str_rec:$pfx_pos_start:$pfx_len}"; 
  58     sfx_pos_start
="$(( pos ))"; 
  59     sfx_len
="$(( len_str_rec - pos ))"; 
  60     sfx
="${str_rec:$sfx_pos_start:$sfx_len}"; 
  62     # Print output to stdout 
  63     printf "%s%s%s\n" "$pfx" "$str_ins" "$sfx"; 
  64 }; # Insert string provided at indicated position via stdout 
  69     if ! ((n_ln 
% "$skip_every")); then 
  73 }; # periodically print separating blank line 
  75     # Desc: Get from 'date' the timezone UTC offset in a way 
  76     #   compatible with both GNU Coreutils and BSD versions. 
  77     # Input: env var: TZ  (time zone for date; e.g. 'America/Denver') 
  78     #        args: $@     # passed onto `date` 
  79     # Depends: date (GNU Coreutils 8.32 or BSD), rev 
  80     local ntz ntz ntz_out
; 
  83     # Get numeric time zone string in way compatible with GNU Coreutils and BSD 
  84     ntz
="$(date "+%z
" "$@
")"; # e.g. "+0530" 
  86     # Check if last two characters are trailing zeros that can be removed. 
  87     last2
="${ntz:3:2}"; # assumes $ntz is 5 characters (i.e. "±HHMM") 
  88     #last2="$(rev <<< $ntz)" && last2="${last2:0:2}" && last2="$(rev <<< "$last2")"; 
  89     if [[ "$last2" == "00" ]]; then 
  90         ## ntz_out is truncated by 2 characters 
  92         len_ntz_out
="$(( len_ntz - 2 ))"; 
  93         ntz_out
=""${ntz:0:$len_ntz_out}; 
  95         ## ntz_out is ntz with semicolon inserted after HH 
  96         ntz_out
="$(insertStr "$ntz" 3 ":" )"; 
 100     printf "%s" "$ntz_out"; 
 101 }; # Format numeric time zone (for BSD date compatibility) 
 107     #        args: $@   # passed on to `date` 
 108     #        env var: TZ (time zone for date; e.g. 'America/Denver') 
 110     # Depends: printf, date 
 112     # Ref/Attrib: * Truncate string in printf https://stackoverflow.com/a/46812677 
 113     local s_1 s_2 s_2_tz s_3 s_4
; 
 116     s_2
="$(date "$@
" "$fs_1")"; # ISO-8601 without numeric timezone 
 117     s_3
="$(date "$@
" "$fs_2")"; # Alternate ISO-8601 expressions 
 118     s_4
="$(date "$@
" "$fs_3")"; # locale-specific date strings 
 120     # Append numeric timezone to $s_2 with appropriate format 
 121     #   (e.g. '-07' for 'Arizona', '+05:45' for 'Asia/Kathmandu') 
 122     s_2_tz
="$(get_tz_offset "$@
")"; 
 123     s_2
="$( printf "%s
%s
" "$s_2" "$s_2_tz" )"; 
 125     printf "%-10.10s %-25.25s (%-20.20s) (%s)" "$s_1" "$s_2" "$s_3" "$s_4"; 
 128     unset fs_1 fs_2 fs_3 fs_4
; 
 129     }; # print line of dates 
 131     n_ln
=0; # for line_sep() 
 132     unset LC_TIME
; # Fall back to time zone-specific locale settings. 
 135     fs_iso8601
="+%Y-%m-%dT%H:%M:%S"; # typical ISO-8601 without timezone 
 136     fs_iso8601_etc
="+%G-W%V-%u, %Y-%j"; # alternate ISO-8601 dates 
 137     fs_locale
="+%Z; %A; %c"; # locale-specific date strings 
 139     # vars for print_dateline() 
 141     fs_2
="$fs_iso8601_etc"; 
 144     # UTC (pop. (2021): 7,837,000,000) 
 148         fs_3
="+%s seconds since 1970-01-01T00:00+00"; 
 155         export LANG
="haw-US.UTF8"; 
 162         export TZ
=America
/Los_Angeles
; 
 163         export LANG
="en_US.UTF-8"; 
 168     # Denver, USA (pop. (2021): 711,463) 
 170         export TZ
=America
/Denver
; 
 171         export LANG
="en_US.UTF-8"; 
 176     # Chicago, USA (pop. (2021): 711,463) 
 178         export TZ
=America
/Chicago
; 
 179         export LANG
="en_US.UTF-8"; 
 184     # Mexico City, Mexico (pop. (2018): 21,804,515) 
 186         export TZ
=America
/Mexico_City
; 
 187         export LANG
="es_MX.UTF8"; 
 192     # Panama City, Panama 
 194         export TZ
=America
/Panama
; 
 195         export LANG
="es_PA.UTF8"; 
 200     # New York, USA (pop. (2018): 20,140,470) 
 202         export TZ
=America
/New_York
; 
 203         export LANG
="en_US.UTF-8"; 
 210         export TZ
=America
/Sao_Paulo
; 
 211         export LANG
="pt_BR.UTF8"; 
 218         export TZ
=America
/Argentina
/Buenos_Aires
; 
 219         export LANG
="es_AR.UTF8"; 
 226         export TZ
=Europe
/London
; 
 227         export LANG
="en_GB.UTF-8"; 
 234         export TZ
=Africa
/Kinshasa
; 
 235         export LANG
="ln_CD.UTF8"; 
 242         export TZ
=Africa
/Lagos
; 
 243         export LANG
="en_NG.UTF8"; 
 250         export TZ
=Europe
/Paris
; 
 251         export LANG
="fr_FR.UTF8"; 
 258         export TZ
=Europe
/Stockholm
; 
 259         export LANG
="sv_SE.UTF8"; 
 266         export TZ
=Europe
/Helsinki
; 
 267         export LANG
="fi_FI.UTF8"; 
 274         export TZ
=Africa
/Cairo
; 
 275         export LANG
="ar_EG.UTF8"; 
 280     # Gaza City, Palestine (pop. (2017): 590,481) 
 283         export LANG
="ar_JO.UTF-8"; # ar_PS is missing as of 2023-10-18, using ar_JO as closest substitute. 
 288     # Tel Aviv, Israel (pop. (2021): 467,875) 
 290         export TZ
=Asia
/Tel_Aviv
; 
 291         export LANG
="he_IL.UTF-8"; 
 296     # Athens (pop. (2020): 3,526,887) 
 298         export TZ
=Europe
/Athens
; 
 299         export LANG
="el_GR.UTF8"; 
 304     # Istanbul (pop. (2020): 13,719,061) 
 306         export TZ
=Asia
/Istanbul
; 
 307         export LANG
="tr_TR.UTF8"; 
 314         export TZ
=Asia
/Tehran
; 
 315         export LANG
="fa_IR.UTF8"; 
 322         export TZ
=Europe
/Moscow
; 
 323         export LANG
="ru_RU.UTF-8"; 
 328     # Kyiv, Ukraine (pop. (2021): 2,962,180) 
 330         export TZ
=Europe
/Kyiv
; 
 331         export LANG
="uk_UA.UTF-8"; 
 336     # Delhi, India (pop. (2018): 29,000,000) 
 338         export TZ
=Asia
/Kolkata
; 
 339         export LANG
="hi_IN.UTF-8"; 
 344     # Jakarta, Indonesia (pop. (2018): 33,430,285) 
 346         export TZ
=Asia
/Jakarta
; 
 347         export LANG
="id_ID.UTF8"; 
 352     # Singapore, Singapore (pop (2018): 5,792,000) 
 354         export TZ
=Asia
/Singapore
; 
 355         export LANG
="en_SG.UTF-8"; 
 360     # Beijing, China (pop. (2018): 19,618,000) 
 362         export TZ
=Asia
/Shanghai
; # [3] 
 363         export LANG
="zh_CN.UTF-8"; 
 368     # Taipei, Taiwan (pop (2019): 7,034,084) 
 370         export TZ
=Asia
/Taipei
; # [3] 
 371         export LANG
="zh_TW.UTF-8"; 
 376     # Tokyo, Japan (pop. (2018): 37,274,000) 
 378         export TZ
=Asia
/Tokyo
; 
 379         export LANG
="ja_JP.UTF8"; 
 384     # Seoul, South Korea (pop. (2018): 25,514,000) 
 386         export TZ
=Asia
/Seoul
; 
 387         export LANG
="ko_KR.UTF8"; 
 392     # Pyongyang, North Korea 
 394         export TZ
=Asia
/Pyongyang
; 
 395         export LANG
="ko_KP.UTF8"; 
 402         export TZ
=Australia
/Sydney
; 
 403         export LANG
="en_AU.UTF8"; 
 410         export TZ
=Pacific
/Guam
; 
 411         export LANG
="en_GU.UTF8"; 
 416     # Auckland, New Zealand 
 418         export TZ
=Pacific
/Auckland
; 
 419         export LANG
="en_NZ.UTF8"; 
 429 # Author: Steven Baltakatei Sandoval