X-Git-Url: https://zdv2.bktei.com/gitweb/BK-2020-03.git/blobdiff_plain/06ff9ce109f7151e0ddf2dfcf9ad8f811a40d989..1deac7e514800559fc8b8bdd7cf3db083d8d5f9e:/user/bkdatev diff --git a/user/bkdatev b/user/bkdatev index 22ff310..cea6883 100755 --- a/user/bkdatev +++ b/user/bkdatev @@ -2,7 +2,8 @@ # Desc: Baltakatei's verbose date command # Usage: bkdatev [args] # Example: bkdatev --date="2001-09-11T09:02:59-04" -# Version: 0.2.2 +# Version: 1.0.0 +# Depends: GNU Coreutils 8.32, Bash 3.2.57 # Ref/Attrib: [1] "ISO 8601". Wikipedia. https://en.wikipedia.org/wiki/ISO_8601 # [2] "Changing the Locale in Wine" https://stackoverflow.com/a/16428951 # [3] "Shanghai vs Beijing" https://bugs.launchpad.net/ubuntu/+source/libgweather/+bug/228554 @@ -11,7 +12,56 @@ # * For list of valid locales, see: https://manpages.ubuntu.com/manpages/bionic/man3/DateTime::Locale::Catalog.3pm.html # * Locations chosen for population, personal signifiance, and spatial coverage. # * For International Atomic Time (TAI), use offsets from UTC provided in `/usr/share/zoneinfo/leap-seconds.list`. - +# * Compatibility with macOS may be limited if any arguments +# are provided when running `bkdatev`; e.g. passing a +# `--date` option to `bkdatev` will fail. + +yell() { echo "$0: $*" >&2; } +die() { yell "$*"; exit 111; } +must() { "$@" || die "cannot $*"; } +insertStr() { + # Desc: Inserts a string into another string at a specified position. + # Input: arg1: str str_rec String to receive insertion + # arg2: int pos Insertion position (0 = append to front) + # arg3: str str_ins String to be inserted + # Output: stdout: Combined string + # Version: 0.0.2 + # Depends: BK-2020-03: yell(), die(), must() + # Ref/Attrib: * BK-2020-03: https://gitlab.com/baltakatei/baltakatei-exdev/ + # * Cooper, Mendel. “Advanced Bash-Scripting Guide: Manipulating Strings”. tldp.org https://tldp.org/LDP/abs/html/string-manipulation.html + + local str_rec pos str_ins re len_str_rec; + local pfx_pos_start pfx_len pfx; + local sfx_pos_start sfx_len sfx; + + # Check args + if [[ $# -ne 3 ]]; then + yell "ERROR:Invalid argument count:$#"; + return 1; fi; + re='^[0-9]+$'; + if [[ ! "$2" =~ $re ]]; then + yell "ERROR:Not an int:$2"; + return 1; fi; + str_rec="$1"; + pos="$2"; + str_ins="$3"; + + # Calculate string stats + len_str_rec="${#str_rec}"; + + # Form prefix + pfx_pos_start="0"; + pfx_len="$pos"; + pfx="${str_rec:$pfx_pos_start:$pfx_len}"; + + # Form suffix + sfx_pos_start="$(( pos ))"; + sfx_len="$(( len_str_rec - pos ))"; + sfx="${str_rec:$sfx_pos_start:$sfx_len}"; + + # Print output to stdout + printf "%s%s%s\n" "$pfx" "$str_ins" "$sfx"; +}; # Insert string provided at indicated position via stdout line_sep() { # Input: var: n_ln local skip_every=4; @@ -21,21 +71,56 @@ line_sep() { fi; return 0; }; # periodically print separating blank line +get_tz_offset() { + # Desc: Get from 'date' the timezone UTC offset in a way + # compatible with both GNU Coreutils and BSD versions. + # Input: env var: TZ (time zone for date; e.g. 'America/Denver') + # args: $@ # passed onto `date` + # Depends: date (GNU Coreutils 8.32 or BSD), rev + local ntz ntz ntz_out; + local last2; + + # Get numeric time zone string in way compatible with GNU Coreutils and BSD + ntz="$(date "+%z" "$@")"; # e.g. "+0530" + + # Check if last two characters are trailing zeros that can be removed. + last2="${ntz:3:2}"; # assumes $ntz is 5 characters (i.e. "±HHMM") + #last2="$(rev <<< $ntz)" && last2="${last2:0:2}" && last2="$(rev <<< "$last2")"; + if [[ "$last2" == "00" ]]; then + ## ntz_out is truncated by 2 characters + len_ntz="${#ntz}"; + len_ntz_out="$(( len_ntz - 2 ))"; + ntz_out=""${ntz:0:$len_ntz_out}; + else + ## ntz_out is ntz with semicolon inserted after HH + ntz_out="$(insertStr "$ntz" 3 ":" )"; + fi; + + # Output via stdout + printf "%s" "$ntz_out"; +}; # Format numeric time zone (for BSD date compatibility) print_dateline() { # Input: var: $id # var: $fs_1 # var: $fs_2 # var: $fs_3 - # args: $@ + # args: $@ # passed on to `date` + # env var: TZ (time zone for date; e.g. 'America/Denver') # Output: stdout # Depends: printf, date + # get_tz_offset() # Ref/Attrib: * Truncate string in printf https://stackoverflow.com/a/46812677 - local s_1 s_2 s_3 s_4; + local s_1 s_2 s_2_tz s_3 s_4; s_1="$id"; - s_2="$(date "$@" "$fs_1")"; - s_3="$(date "$@" "$fs_2")"; - s_4="$(date "$@" "$fs_3")"; + s_2="$(date "$@" "$fs_1")"; # ISO-8601 without numeric timezone + s_3="$(date "$@" "$fs_2")"; # Alternate ISO-8601 expressions + s_4="$(date "$@" "$fs_3")"; # locale-specific date strings + + # Append numeric timezone to $s_2 with appropriate format + # (e.g. '-07' for 'Arizona', '+05:45' for 'Asia/Kathmandu') + s_2_tz="$(get_tz_offset "$@")"; + s_2="$( printf "%s%s" "$s_2" "$s_2_tz" )"; printf "%-10.10s %-25.25s (%-20.20s) (%s)" "$s_1" "$s_2" "$s_3" "$s_4"; printf "\n"; @@ -47,7 +132,7 @@ main() { unset LC_TIME; # Fall back to time zone-specific locale settings. # format strings - fs_iso8601="+%Y-%m-%dT%H:%M:%S%:::z"; # typical ISO-8601 + fs_iso8601="+%Y-%m-%dT%H:%M:%S"; # typical ISO-8601 without timezone fs_iso8601_etc="+%G-W%V-%u, %Y-%j"; # alternate ISO-8601 dates fs_locale="+%Z; %A; %c"; # locale-specific date strings @@ -176,6 +261,14 @@ main() { print_dateline "$@"; ); line_sep; + # Helsinki, Finland + ( + export TZ=Europe/Helsinki; + export LANG="fi_FI.UTF8"; + id="HELSINKI"; + print_dateline "$@"; + ); line_sep; + # Cairo, Egypt ( export TZ=Africa/Cairo; @@ -184,6 +277,22 @@ main() { print_dateline "$@"; ); line_sep; + # Gaza City, Palestine (pop. (2017): 590,481) + ( + export TZ=Asia/Gaza; + export LANG="ar_JO.UTF-8"; # ar_PS is missing as of 2023-10-18, using ar_JO as closest substitute. + id="GAZA"; + print_dateline "$@"; + ); line_sep; + + # Tel Aviv, Israel (pop. (2021): 467,875) + ( + export TZ=Asia/Tel_Aviv; + export LANG="he_IL.UTF-8"; + id="TEL AVIV"; + print_dateline "$@"; + ); line_sep; + # Athens (pop. (2020): 3,526,887) ( export TZ=Europe/Athens; @@ -316,3 +425,6 @@ main() { }; # main program main "$@"; + +# Author: Steven Baltakatei Sandoval +# License: GPLv3+