1bc421551SDag-Erling Smørgrav#!/bin/bash 2bc421551SDag-Erling Smørgrav# Ask the user about the time zone, and output the resulting TZ value to stdout. 3bc421551SDag-Erling Smørgrav# Interact with the user via stderr and stdin. 4bc421551SDag-Erling Smørgrav 5bc421551SDag-Erling SmørgravPKGVERSION='(tzcode) ' 6bc421551SDag-Erling SmørgravTZVERSION=see_Makefile 7bc421551SDag-Erling SmørgravREPORT_BUGS_TO=tz@iana.org 8bc421551SDag-Erling Smørgrav 9bc421551SDag-Erling Smørgrav# Contributed by Paul Eggert. This file is in the public domain. 10bc421551SDag-Erling Smørgrav 11bc421551SDag-Erling Smørgrav# Porting notes: 12bc421551SDag-Erling Smørgrav# 1346c59934SDag-Erling Smørgrav# This script requires a POSIX-like shell and prefers the extension of a 14bc421551SDag-Erling Smørgrav# 'select' statement. The 'select' statement was introduced in the 15bc421551SDag-Erling Smørgrav# Korn shell and is available in Bash and other shell implementations. 16bc421551SDag-Erling Smørgrav# If your host lacks both Bash and the Korn shell, you can get their 17bc421551SDag-Erling Smørgrav# source from one of these locations: 18bc421551SDag-Erling Smørgrav# 19bc421551SDag-Erling Smørgrav# Bash <https://www.gnu.org/software/bash/> 20bc421551SDag-Erling Smørgrav# Korn Shell <http://www.kornshell.com/> 21bc421551SDag-Erling Smørgrav# MirBSD Korn Shell <http://www.mirbsd.org/mksh.htm> 22bc421551SDag-Erling Smørgrav# 2346c59934SDag-Erling Smørgrav# This script also uses several features of POSIX awk. 2446c59934SDag-Erling Smørgrav# If your host lacks awk, or has an old awk that does not conform to POSIX, 2546c59934SDag-Erling Smørgrav# you can use any of the following free programs instead: 26bc421551SDag-Erling Smørgrav# 27bc421551SDag-Erling Smørgrav# Gawk (GNU awk) <https://www.gnu.org/software/gawk/> 28bc421551SDag-Erling Smørgrav# mawk <https://invisible-island.net/mawk/> 29bc421551SDag-Erling Smørgrav# nawk <https://github.com/onetrueawk/awk> 3046c59934SDag-Erling Smørgrav# 3146c59934SDag-Erling Smørgrav# Because 'awk "VAR=VALUE" ...' and 'awk -v "VAR=VALUE" ...' are not portable 3246c59934SDag-Erling Smørgrav# if VALUE contains \, ", or newline, awk scripts in this file use: 3346c59934SDag-Erling Smørgrav# awk 'BEGIN { VAR = substr(ARGV[1], 2); ARGV[1] = "" } ...' ="VALUE" 3446c59934SDag-Erling Smørgrav# The substr avoids problems when VALUE is of the form X=Y and would be 3546c59934SDag-Erling Smørgrav# misinterpreted as an assignment. 36bc421551SDag-Erling Smørgrav 3746c59934SDag-Erling Smørgrav# This script does not want path expansion. 3846c59934SDag-Erling Smørgravset -f 39bc421551SDag-Erling Smørgrav 40bc421551SDag-Erling Smørgrav# Specify default values for environment variables if they are unset. 41bc421551SDag-Erling Smørgrav: ${AWK=awk} 4246c59934SDag-Erling Smørgrav: ${TZDIR=$PWD} 43bc421551SDag-Erling Smørgrav 4475411d15SDag-Erling Smørgrav# Output one argument as-is to standard output, with trailing newline. 45bc421551SDag-Erling Smørgrav# Safer than 'echo', which can mishandle '\' or leading '-'. 46bc421551SDag-Erling Smørgravsay() { 47bc421551SDag-Erling Smørgrav printf '%s\n' "$1" 48bc421551SDag-Erling Smørgrav} 49bc421551SDag-Erling Smørgrav 50bc421551SDag-Erling Smørgravcoord= 51bc421551SDag-Erling Smørgravlocation_limit=10 52bc421551SDag-Erling Smørgravzonetabtype=zone1970 53bc421551SDag-Erling Smørgrav 54bc421551SDag-Erling Smørgravusage="Usage: tzselect [--version] [--help] [-c COORD] [-n LIMIT] 55bc421551SDag-Erling SmørgravSelect a timezone interactively. 56bc421551SDag-Erling Smørgrav 57bc421551SDag-Erling SmørgravOptions: 58bc421551SDag-Erling Smørgrav 59bc421551SDag-Erling Smørgrav -c COORD 60bc421551SDag-Erling Smørgrav Instead of asking for continent and then country and then city, 61bc421551SDag-Erling Smørgrav ask for selection from time zones whose largest cities 62bc421551SDag-Erling Smørgrav are closest to the location with geographical coordinates COORD. 63bc421551SDag-Erling Smørgrav COORD should use ISO 6709 notation, for example, '-c +4852+00220' 64bc421551SDag-Erling Smørgrav for Paris (in degrees and minutes, North and East), or 65bc421551SDag-Erling Smørgrav '-c -35-058' for Buenos Aires (in degrees, South and West). 66bc421551SDag-Erling Smørgrav 67bc421551SDag-Erling Smørgrav -n LIMIT 68bc421551SDag-Erling Smørgrav Display at most LIMIT locations when -c is used (default $location_limit). 69bc421551SDag-Erling Smørgrav 70bc421551SDag-Erling Smørgrav --version 71bc421551SDag-Erling Smørgrav Output version information. 72bc421551SDag-Erling Smørgrav 73bc421551SDag-Erling Smørgrav --help 74bc421551SDag-Erling Smørgrav Output this help. 75bc421551SDag-Erling Smørgrav 76bc421551SDag-Erling SmørgravReport bugs to $REPORT_BUGS_TO." 77bc421551SDag-Erling Smørgrav 78bc421551SDag-Erling Smørgrav# Ask the user to select from the function's arguments, 79bc421551SDag-Erling Smørgrav# and assign the selected argument to the variable 'select_result'. 8075411d15SDag-Erling Smørgrav# Exit on EOF or I/O error. Use the shell's nicer 'select' builtin if 8175411d15SDag-Erling Smørgrav# available, falling back on a portable substitute otherwise. 82bc421551SDag-Erling Smørgravif 83bc421551SDag-Erling Smørgrav case $BASH_VERSION in 84bc421551SDag-Erling Smørgrav ?*) :;; 85bc421551SDag-Erling Smørgrav '') 86bc421551SDag-Erling Smørgrav # '; exit' should be redundant, but Dash doesn't properly fail without it. 8746c59934SDag-Erling Smørgrav (eval 'set --; select x; do break; done; exit') <>/dev/null 2>&0 88bc421551SDag-Erling Smørgrav esac 89bc421551SDag-Erling Smørgravthen 90bc421551SDag-Erling Smørgrav # Do this inside 'eval', as otherwise the shell might exit when parsing it 91bc421551SDag-Erling Smørgrav # even though it is never executed. 92bc421551SDag-Erling Smørgrav eval ' 93bc421551SDag-Erling Smørgrav doselect() { 94bc421551SDag-Erling Smørgrav select select_result 95bc421551SDag-Erling Smørgrav do 96bc421551SDag-Erling Smørgrav case $select_result in 97bc421551SDag-Erling Smørgrav "") echo >&2 "Please enter a number in range.";; 98bc421551SDag-Erling Smørgrav ?*) break 99bc421551SDag-Erling Smørgrav esac 100bc421551SDag-Erling Smørgrav done || exit 101bc421551SDag-Erling Smørgrav } 102bc421551SDag-Erling Smørgrav ' 103bc421551SDag-Erling Smørgravelse 104bc421551SDag-Erling Smørgrav doselect() { 105bc421551SDag-Erling Smørgrav # Field width of the prompt numbers. 106*a979394aSDag-Erling Smørgrav select_width=${##} 107bc421551SDag-Erling Smørgrav 108bc421551SDag-Erling Smørgrav select_i= 109bc421551SDag-Erling Smørgrav 110bc421551SDag-Erling Smørgrav while : 111bc421551SDag-Erling Smørgrav do 112bc421551SDag-Erling Smørgrav case $select_i in 113bc421551SDag-Erling Smørgrav '') 114bc421551SDag-Erling Smørgrav select_i=0 115bc421551SDag-Erling Smørgrav for select_word 116bc421551SDag-Erling Smørgrav do 117*a979394aSDag-Erling Smørgrav select_i=$(($select_i + 1)) 118bc421551SDag-Erling Smørgrav printf >&2 "%${select_width}d) %s\\n" $select_i "$select_word" 119bc421551SDag-Erling Smørgrav done;; 120bc421551SDag-Erling Smørgrav *[!0-9]*) 121bc421551SDag-Erling Smørgrav echo >&2 'Please enter a number in range.';; 122bc421551SDag-Erling Smørgrav *) 123bc421551SDag-Erling Smørgrav if test 1 -le $select_i && test $select_i -le $#; then 124*a979394aSDag-Erling Smørgrav shift $(($select_i - 1)) 125bc421551SDag-Erling Smørgrav select_result=$1 126bc421551SDag-Erling Smørgrav break 127bc421551SDag-Erling Smørgrav fi 128bc421551SDag-Erling Smørgrav echo >&2 'Please enter a number in range.' 129bc421551SDag-Erling Smørgrav esac 130bc421551SDag-Erling Smørgrav 131bc421551SDag-Erling Smørgrav # Prompt and read input. 132bc421551SDag-Erling Smørgrav printf >&2 %s "${PS3-#? }" 133bc421551SDag-Erling Smørgrav read select_i || exit 134bc421551SDag-Erling Smørgrav done 135bc421551SDag-Erling Smørgrav } 136bc421551SDag-Erling Smørgravfi 137bc421551SDag-Erling Smørgrav 138bc421551SDag-Erling Smørgravwhile getopts c:n:t:-: opt 139bc421551SDag-Erling Smørgravdo 140bc421551SDag-Erling Smørgrav case $opt$OPTARG in 141bc421551SDag-Erling Smørgrav c*) 142bc421551SDag-Erling Smørgrav coord=$OPTARG;; 143bc421551SDag-Erling Smørgrav n*) 144bc421551SDag-Erling Smørgrav location_limit=$OPTARG;; 145bc421551SDag-Erling Smørgrav t*) # Undocumented option, used for developer testing. 146bc421551SDag-Erling Smørgrav zonetabtype=$OPTARG;; 147bc421551SDag-Erling Smørgrav -help) 148bc421551SDag-Erling Smørgrav exec echo "$usage";; 149bc421551SDag-Erling Smørgrav -version) 150bc421551SDag-Erling Smørgrav exec echo "tzselect $PKGVERSION$TZVERSION";; 151bc421551SDag-Erling Smørgrav -*) 152bc421551SDag-Erling Smørgrav say >&2 "$0: -$opt$OPTARG: unknown option; try '$0 --help'"; exit 1;; 153bc421551SDag-Erling Smørgrav *) 15446c59934SDag-Erling Smørgrav say >&2 "$0: try '$0 --help'"; exit 1 155bc421551SDag-Erling Smørgrav esac 156bc421551SDag-Erling Smørgravdone 157bc421551SDag-Erling Smørgrav 158*a979394aSDag-Erling Smørgravshift $(($OPTIND - 1)) 159bc421551SDag-Erling Smørgravcase $# in 160bc421551SDag-Erling Smørgrav0) ;; 16146c59934SDag-Erling Smørgrav*) say >&2 "$0: $1: unknown argument"; exit 1 162bc421551SDag-Erling Smørgravesac 163bc421551SDag-Erling Smørgrav 16446c59934SDag-Erling Smørgrav# translit=true to try transliteration. 16546c59934SDag-Erling Smørgrav# This is false if U+12345 CUNEIFORM SIGN URU TIMES KI has length 1 166*a979394aSDag-Erling Smørgrav# which means the shell and (presumably) awk do not need transliteration. 167*a979394aSDag-Erling Smørgrav# It is true if the byte string has some other length in characters, or 168*a979394aSDag-Erling Smørgrav# if this is a POSIX.1-2017 or earlier shell that does not support $'...'. 169*a979394aSDag-Erling SmørgravCUNEIFORM_SIGN_URU_TIMES_KI=$'\360\222\215\205' 170*a979394aSDag-Erling Smørgravif test ${#CUNEIFORM_SIGN_URU_TIMES_KI} = 1 171*a979394aSDag-Erling Smørgravthen translit=false 172*a979394aSDag-Erling Smørgravelse translit=true 17346c59934SDag-Erling Smørgravfi 17446c59934SDag-Erling Smørgrav 17546c59934SDag-Erling Smørgrav# Read into shell variable $1 the contents of file $2. 17646c59934SDag-Erling Smørgrav# Convert to the current locale's encoding if possible, 17746c59934SDag-Erling Smørgrav# as the shell aligns columns better that way. 17846c59934SDag-Erling Smørgrav# If GNU iconv's //TRANSLIT does not work, fall back on POSIXish iconv; 17946c59934SDag-Erling Smørgrav# if that does not work, fall back on 'cat'. 18046c59934SDag-Erling Smørgravread_file() { 18146c59934SDag-Erling Smørgrav { $translit && { 182*a979394aSDag-Erling Smørgrav eval "$1=\$( (iconv -f UTF-8 -t //TRANSLIT) 2>/dev/null <\"\$2\")" || 183*a979394aSDag-Erling Smørgrav eval "$1=\$( (iconv -f UTF-8) 2>/dev/null <\"\$2\")" 18446c59934SDag-Erling Smørgrav }; } || 185*a979394aSDag-Erling Smørgrav eval "$1=\$(cat <\"\$2\")" || { 186bc421551SDag-Erling Smørgrav say >&2 "$0: time zone files are not set up correctly" 187bc421551SDag-Erling Smørgrav exit 1 188bc421551SDag-Erling Smørgrav } 189bc421551SDag-Erling Smørgrav} 19046c59934SDag-Erling Smørgravread_file TZ_COUNTRY_TABLE "$TZDIR/iso3166.tab" 19146c59934SDag-Erling Smørgravread_file TZ_ZONETABTYPE_TABLE "$TZDIR/$zonetabtype.tab" 19246c59934SDag-Erling SmørgravTZ_ZONENOW_TABLE= 193bc421551SDag-Erling Smørgrav 194bc421551SDag-Erling Smørgravnewline=' 195bc421551SDag-Erling Smørgrav' 196bc421551SDag-Erling SmørgravIFS=$newline 197bc421551SDag-Erling Smørgrav 19875411d15SDag-Erling Smørgrav# Awk script to output a country list. 19975411d15SDag-Erling Smørgravoutput_country_list=' 20046c59934SDag-Erling Smørgrav BEGIN { 20146c59934SDag-Erling Smørgrav continent_re = substr(ARGV[1], 2) 20246c59934SDag-Erling Smørgrav TZ_COUNTRY_TABLE = substr(ARGV[2], 2) 20346c59934SDag-Erling Smørgrav TZ_ZONE_TABLE = substr(ARGV[3], 2) 20446c59934SDag-Erling Smørgrav ARGV[1] = ARGV[2] = ARGV[3] = "" 20546c59934SDag-Erling Smørgrav FS = "\t" 20646c59934SDag-Erling Smørgrav nlines = split(TZ_ZONE_TABLE, line, /\n/) 20746c59934SDag-Erling Smørgrav for (iline = 1; iline <= nlines; iline++) { 20846c59934SDag-Erling Smørgrav $0 = line[iline] 20975411d15SDag-Erling Smørgrav commentary = $0 ~ /^#@/ 21075411d15SDag-Erling Smørgrav if (commentary) { 21146c59934SDag-Erling Smørgrav if ($0 !~ /^#@/) 21246c59934SDag-Erling Smørgrav continue 21375411d15SDag-Erling Smørgrav col1ccs = substr($1, 3) 21475411d15SDag-Erling Smørgrav conts = $2 21575411d15SDag-Erling Smørgrav } else { 21675411d15SDag-Erling Smørgrav col1ccs = $1 21775411d15SDag-Erling Smørgrav conts = $3 21875411d15SDag-Erling Smørgrav } 21975411d15SDag-Erling Smørgrav ncc = split(col1ccs, cc, /,/) 22075411d15SDag-Erling Smørgrav ncont = split(conts, cont, /,/) 22175411d15SDag-Erling Smørgrav for (i = 1; i <= ncc; i++) { 22275411d15SDag-Erling Smørgrav elsewhere = commentary 22375411d15SDag-Erling Smørgrav for (ci = 1; ci <= ncont; ci++) { 22475411d15SDag-Erling Smørgrav if (cont[ci] ~ continent_re) { 22546c59934SDag-Erling Smørgrav if (!cc_seen[cc[i]]++) 22646c59934SDag-Erling Smørgrav cc_list[++ccs] = cc[i] 22775411d15SDag-Erling Smørgrav elsewhere = 0 22875411d15SDag-Erling Smørgrav } 22975411d15SDag-Erling Smørgrav } 23046c59934SDag-Erling Smørgrav if (elsewhere) 23146c59934SDag-Erling Smørgrav for (i = 1; i <= ncc; i++) 23275411d15SDag-Erling Smørgrav cc_elsewhere[cc[i]] = 1 23375411d15SDag-Erling Smørgrav } 23475411d15SDag-Erling Smørgrav } 23546c59934SDag-Erling Smørgrav nlines = split(TZ_COUNTRY_TABLE, line, /\n/) 23646c59934SDag-Erling Smørgrav for (i = 1; i <= nlines; i++) { 23746c59934SDag-Erling Smørgrav $0 = line[i] 23846c59934SDag-Erling Smørgrav if ($0 !~ /^#/) 23946c59934SDag-Erling Smørgrav cc_name[$1] = $2 24075411d15SDag-Erling Smørgrav } 24175411d15SDag-Erling Smørgrav for (i = 1; i <= ccs; i++) { 24275411d15SDag-Erling Smørgrav country = cc_list[i] 24346c59934SDag-Erling Smørgrav if (cc_elsewhere[country]) 24446c59934SDag-Erling Smørgrav continue 24546c59934SDag-Erling Smørgrav if (cc_name[country]) 24675411d15SDag-Erling Smørgrav country = cc_name[country] 24775411d15SDag-Erling Smørgrav print country 24875411d15SDag-Erling Smørgrav } 24975411d15SDag-Erling Smørgrav } 25075411d15SDag-Erling Smørgrav' 251bc421551SDag-Erling Smørgrav 25246c59934SDag-Erling Smørgrav# Awk script to process a time zone table and output the same table, 25375411d15SDag-Erling Smørgrav# with each row preceded by its distance from 'here'. 25475411d15SDag-Erling Smørgrav# If output_times is set, each row is instead preceded by its local time 25575411d15SDag-Erling Smørgrav# and any apostrophes are escaped for the shell. 25675411d15SDag-Erling Smørgravoutput_distances_or_times=' 257bc421551SDag-Erling Smørgrav BEGIN { 25846c59934SDag-Erling Smørgrav coord = substr(ARGV[1], 2) 25946c59934SDag-Erling Smørgrav TZ_COUNTRY_TABLE = substr(ARGV[2], 2) 26046c59934SDag-Erling Smørgrav TZ_ZONE_TABLE = substr(ARGV[3], 2) 26146c59934SDag-Erling Smørgrav ARGV[1] = ARGV[2] = ARGV[3] = "" 262bc421551SDag-Erling Smørgrav FS = "\t" 26375411d15SDag-Erling Smørgrav if (!output_times) { 26446c59934SDag-Erling Smørgrav nlines = split(TZ_COUNTRY_TABLE, line, /\n/) 26546c59934SDag-Erling Smørgrav for (i = 1; i <= nlines; i++) { 26646c59934SDag-Erling Smørgrav $0 = line[i] 26746c59934SDag-Erling Smørgrav if ($0 ~ /^#/) 26846c59934SDag-Erling Smørgrav continue 269bc421551SDag-Erling Smørgrav country[$1] = $2 27046c59934SDag-Erling Smørgrav } 271bc421551SDag-Erling Smørgrav country["US"] = "US" # Otherwise the strings get too long. 272bc421551SDag-Erling Smørgrav } 27375411d15SDag-Erling Smørgrav } 274bc421551SDag-Erling Smørgrav function abs(x) { 275bc421551SDag-Erling Smørgrav return x < 0 ? -x : x; 276bc421551SDag-Erling Smørgrav } 277bc421551SDag-Erling Smørgrav function min(x, y) { 278bc421551SDag-Erling Smørgrav return x < y ? x : y; 279bc421551SDag-Erling Smørgrav } 280bc421551SDag-Erling Smørgrav function convert_coord(coord, deg, minute, ilen, sign, sec) { 281bc421551SDag-Erling Smørgrav if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9][0-9][0-9]([^0-9]|$)/) { 282bc421551SDag-Erling Smørgrav degminsec = coord 283bc421551SDag-Erling Smørgrav intdeg = degminsec < 0 ? -int(-degminsec / 10000) : int(degminsec / 10000) 284bc421551SDag-Erling Smørgrav minsec = degminsec - intdeg * 10000 285bc421551SDag-Erling Smørgrav intmin = minsec < 0 ? -int(-minsec / 100) : int(minsec / 100) 286bc421551SDag-Erling Smørgrav sec = minsec - intmin * 100 287bc421551SDag-Erling Smørgrav deg = (intdeg * 3600 + intmin * 60 + sec) / 3600 288bc421551SDag-Erling Smørgrav } else if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9]([^0-9]|$)/) { 289bc421551SDag-Erling Smørgrav degmin = coord 290bc421551SDag-Erling Smørgrav intdeg = degmin < 0 ? -int(-degmin / 100) : int(degmin / 100) 291bc421551SDag-Erling Smørgrav minute = degmin - intdeg * 100 292bc421551SDag-Erling Smørgrav deg = (intdeg * 60 + minute) / 60 293bc421551SDag-Erling Smørgrav } else 294bc421551SDag-Erling Smørgrav deg = coord 295bc421551SDag-Erling Smørgrav return deg * 0.017453292519943296 296bc421551SDag-Erling Smørgrav } 297bc421551SDag-Erling Smørgrav function convert_latitude(coord) { 298bc421551SDag-Erling Smørgrav match(coord, /..*[-+]/) 299bc421551SDag-Erling Smørgrav return convert_coord(substr(coord, 1, RLENGTH - 1)) 300bc421551SDag-Erling Smørgrav } 301bc421551SDag-Erling Smørgrav function convert_longitude(coord) { 302bc421551SDag-Erling Smørgrav match(coord, /..*[-+]/) 303bc421551SDag-Erling Smørgrav return convert_coord(substr(coord, RLENGTH)) 304bc421551SDag-Erling Smørgrav } 305bc421551SDag-Erling Smørgrav # Great-circle distance between points with given latitude and longitude. 306bc421551SDag-Erling Smørgrav # Inputs and output are in radians. This uses the great-circle special 307bc421551SDag-Erling Smørgrav # case of the Vicenty formula for distances on ellipsoids. 308bc421551SDag-Erling Smørgrav function gcdist(lat1, long1, lat2, long2, dlong, x, y, num, denom) { 309bc421551SDag-Erling Smørgrav dlong = long2 - long1 310bc421551SDag-Erling Smørgrav x = cos(lat2) * sin(dlong) 311bc421551SDag-Erling Smørgrav y = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dlong) 312bc421551SDag-Erling Smørgrav num = sqrt(x * x + y * y) 313bc421551SDag-Erling Smørgrav denom = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(dlong) 314bc421551SDag-Erling Smørgrav return atan2(num, denom) 315bc421551SDag-Erling Smørgrav } 316bc421551SDag-Erling Smørgrav # Parallel distance between points with given latitude and longitude. 317bc421551SDag-Erling Smørgrav # This is the product of the longitude difference and the cosine 318bc421551SDag-Erling Smørgrav # of the latitude of the point that is further from the equator. 319bc421551SDag-Erling Smørgrav # I.e., it considers longitudes to be further apart if they are 320bc421551SDag-Erling Smørgrav # nearer the equator. 321bc421551SDag-Erling Smørgrav function pardist(lat1, long1, lat2, long2) { 322bc421551SDag-Erling Smørgrav return abs(long1 - long2) * min(cos(lat1), cos(lat2)) 323bc421551SDag-Erling Smørgrav } 324bc421551SDag-Erling Smørgrav # The distance function is the sum of the great-circle distance and 325bc421551SDag-Erling Smørgrav # the parallel distance. It could be weighted. 326bc421551SDag-Erling Smørgrav function dist(lat1, long1, lat2, long2) { 327bc421551SDag-Erling Smørgrav return gcdist(lat1, long1, lat2, long2) + pardist(lat1, long1, lat2, long2) 328bc421551SDag-Erling Smørgrav } 329bc421551SDag-Erling Smørgrav BEGIN { 330bc421551SDag-Erling Smørgrav coord_lat = convert_latitude(coord) 331bc421551SDag-Erling Smørgrav coord_long = convert_longitude(coord) 33246c59934SDag-Erling Smørgrav nlines = split(TZ_ZONE_TABLE, line, /\n/) 33346c59934SDag-Erling Smørgrav for (h = 1; h <= nlines; h++) { 33446c59934SDag-Erling Smørgrav $0 = line[h] 33546c59934SDag-Erling Smørgrav if ($0 ~ /^#/) 33646c59934SDag-Erling Smørgrav continue 33775411d15SDag-Erling Smørgrav inline[inlines++] = $0 33875411d15SDag-Erling Smørgrav ncc = split($1, cc, /,/) 33975411d15SDag-Erling Smørgrav for (i = 1; i <= ncc; i++) 34075411d15SDag-Erling Smørgrav cc_used[cc[i]]++ 34175411d15SDag-Erling Smørgrav } 34275411d15SDag-Erling Smørgrav for (h = 0; h < inlines; h++) { 34375411d15SDag-Erling Smørgrav $0 = inline[h] 34446c59934SDag-Erling Smørgrav outline = $1 "\t" $2 "\t" $3 345bc421551SDag-Erling Smørgrav sep = "\t" 346bc421551SDag-Erling Smørgrav ncc = split($1, cc, /,/) 34775411d15SDag-Erling Smørgrav split("", item_seen) 34875411d15SDag-Erling Smørgrav item_seen[""] = 1 349bc421551SDag-Erling Smørgrav for (i = 1; i <= ncc; i++) { 35075411d15SDag-Erling Smørgrav item = cc_used[cc[i]] <= 1 ? country[cc[i]] : $4 35146c59934SDag-Erling Smørgrav if (item_seen[item]++) 35246c59934SDag-Erling Smørgrav continue 35346c59934SDag-Erling Smørgrav outline = outline sep item 35475411d15SDag-Erling Smørgrav sep = "; " 355bc421551SDag-Erling Smørgrav } 35675411d15SDag-Erling Smørgrav if (output_times) { 35775411d15SDag-Erling Smørgrav fmt = "TZ='\''%s'\'' date +'\''%d %%Y %%m %%d %%H:%%M %%a %%b\t%s'\''\n" 35846c59934SDag-Erling Smørgrav gsub(/'\''/, "&\\\\&&", outline) 35946c59934SDag-Erling Smørgrav printf fmt, $3, h, outline 36075411d15SDag-Erling Smørgrav } else { 36175411d15SDag-Erling Smørgrav here_lat = convert_latitude($2) 36275411d15SDag-Erling Smørgrav here_long = convert_longitude($2) 36346c59934SDag-Erling Smørgrav printf "%g\t%s\n", dist(coord_lat, coord_long, here_lat, here_long), \ 36446c59934SDag-Erling Smørgrav outline 365bc421551SDag-Erling Smørgrav } 36675411d15SDag-Erling Smørgrav } 36775411d15SDag-Erling Smørgrav } 368bc421551SDag-Erling Smørgrav' 369bc421551SDag-Erling Smørgrav 370bc421551SDag-Erling Smørgrav# Begin the main loop. We come back here if the user wants to retry. 371bc421551SDag-Erling Smørgravwhile 372bc421551SDag-Erling Smørgrav 373bc421551SDag-Erling Smørgrav echo >&2 'Please identify a location' \ 374bc421551SDag-Erling Smørgrav 'so that time zone rules can be set correctly.' 375bc421551SDag-Erling Smørgrav 376bc421551SDag-Erling Smørgrav continent= 377bc421551SDag-Erling Smørgrav country= 37846c59934SDag-Erling Smørgrav country_result= 379bc421551SDag-Erling Smørgrav region= 38046c59934SDag-Erling Smørgrav time= 38146c59934SDag-Erling Smørgrav TZ_ZONE_TABLE=$TZ_ZONETABTYPE_TABLE 382bc421551SDag-Erling Smørgrav 383bc421551SDag-Erling Smørgrav case $coord in 384bc421551SDag-Erling Smørgrav ?*) 385bc421551SDag-Erling Smørgrav continent=coord;; 386bc421551SDag-Erling Smørgrav '') 387bc421551SDag-Erling Smørgrav 388bc421551SDag-Erling Smørgrav # Ask the user for continent or ocean. 389bc421551SDag-Erling Smørgrav 39046c59934SDag-Erling Smørgrav echo >&2 \ 39146c59934SDag-Erling Smørgrav 'Please select a continent, ocean, "coord", "TZ", "time", or "now".' 392bc421551SDag-Erling Smørgrav 393*a979394aSDag-Erling Smørgrav quoted_continents=$( 394bc421551SDag-Erling Smørgrav $AWK ' 395bc421551SDag-Erling Smørgrav function handle_entry(entry) { 396bc421551SDag-Erling Smørgrav entry = substr(entry, 1, index(entry, "/") - 1) 397bc421551SDag-Erling Smørgrav if (entry == "America") 398bc421551SDag-Erling Smørgrav entry = entry "s" 399bc421551SDag-Erling Smørgrav if (entry ~ /^(Arctic|Atlantic|Indian|Pacific)$/) 400bc421551SDag-Erling Smørgrav entry = entry " Ocean" 401bc421551SDag-Erling Smørgrav printf "'\''%s'\''\n", entry 402bc421551SDag-Erling Smørgrav } 40346c59934SDag-Erling Smørgrav BEGIN { 40446c59934SDag-Erling Smørgrav TZ_ZONETABTYPE_TABLE = substr(ARGV[1], 2) 40546c59934SDag-Erling Smørgrav ARGV[1] = "" 40646c59934SDag-Erling Smørgrav FS = "\t" 40746c59934SDag-Erling Smørgrav nlines = split(TZ_ZONETABTYPE_TABLE, line, /\n/) 40846c59934SDag-Erling Smørgrav for (i = 1; i <= nlines; i++) { 40946c59934SDag-Erling Smørgrav $0 = line[i] 41046c59934SDag-Erling Smørgrav if ($0 ~ /^[^#]/) 411bc421551SDag-Erling Smørgrav handle_entry($3) 41246c59934SDag-Erling Smørgrav else if ($0 ~ /^#@/) { 413bc421551SDag-Erling Smørgrav ncont = split($2, cont, /,/) 41446c59934SDag-Erling Smørgrav for (ci = 1; ci <= ncont; ci++) 415bc421551SDag-Erling Smørgrav handle_entry(cont[ci]) 416bc421551SDag-Erling Smørgrav } 417bc421551SDag-Erling Smørgrav } 41846c59934SDag-Erling Smørgrav } 41946c59934SDag-Erling Smørgrav ' ="$TZ_ZONETABTYPE_TABLE" | 420bc421551SDag-Erling Smørgrav sort -u | 421bc421551SDag-Erling Smørgrav tr '\n' ' ' 422bc421551SDag-Erling Smørgrav echo '' 423*a979394aSDag-Erling Smørgrav ) 424bc421551SDag-Erling Smørgrav 425bc421551SDag-Erling Smørgrav eval ' 426bc421551SDag-Erling Smørgrav doselect '"$quoted_continents"' \ 427bc421551SDag-Erling Smørgrav "coord - I want to use geographical coordinates." \ 428*a979394aSDag-Erling Smørgrav "TZ - I want to specify the timezone using a proleptic TZ string." \ 42946c59934SDag-Erling Smørgrav "time - I know local time already." \ 43046c59934SDag-Erling Smørgrav "now - Like \"time\", but configure only for timestamps from now on." 431bc421551SDag-Erling Smørgrav continent=$select_result 432bc421551SDag-Erling Smørgrav case $continent in 433bc421551SDag-Erling Smørgrav Americas) continent=America;; 43446c59934SDag-Erling Smørgrav *) 43546c59934SDag-Erling Smørgrav # Get the first word of $continent. Path expansion is disabled 43646c59934SDag-Erling Smørgrav # so this works even with "*", which should not happen. 43746c59934SDag-Erling Smørgrav IFS=" " 43846c59934SDag-Erling Smørgrav for continent in $continent ""; do break; done 43946c59934SDag-Erling Smørgrav IFS=$newline;; 44046c59934SDag-Erling Smørgrav esac 44146c59934SDag-Erling Smørgrav case $zonetabtype,$continent in 44246c59934SDag-Erling Smørgrav zonenow,*) ;; 44346c59934SDag-Erling Smørgrav *,now) 44446c59934SDag-Erling Smørgrav ${TZ_ZONENOW_TABLE:+:} read_file TZ_ZONENOW_TABLE "$TZDIR/zonenow.tab" 44546c59934SDag-Erling Smørgrav TZ_ZONE_TABLE=$TZ_ZONENOW_TABLE 446bc421551SDag-Erling Smørgrav esac 447bc421551SDag-Erling Smørgrav ' 448bc421551SDag-Erling Smørgrav esac 449bc421551SDag-Erling Smørgrav 450bc421551SDag-Erling Smørgrav case $continent in 451bc421551SDag-Erling Smørgrav TZ) 452*a979394aSDag-Erling Smørgrav # Ask the user for a proleptic TZ string. Check that it conforms. 45346c59934SDag-Erling Smørgrav check_POSIX_TZ_string=' 45446c59934SDag-Erling Smørgrav BEGIN { 45546c59934SDag-Erling Smørgrav tz = substr(ARGV[1], 2) 45646c59934SDag-Erling Smørgrav ARGV[1] = "" 45746c59934SDag-Erling Smørgrav tzname = ("(<[[:alnum:]+-][[:alnum:]+-][[:alnum:]+-]+>" \ 45846c59934SDag-Erling Smørgrav "|[[:alpha:]][[:alpha:]][[:alpha:]]+)") 459*a979394aSDag-Erling Smørgrav sign = "[-+]?" 460*a979394aSDag-Erling Smørgrav hhmm = "(:[0-5][0-9](:[0-5][0-9])?)?" 461*a979394aSDag-Erling Smørgrav offset = sign "(2[0-4]|[0-1]?[0-9])" hhmm 462*a979394aSDag-Erling Smørgrav time = sign "(16[0-7]|(1[0-5]|[0-9]?)[0-9])" hhmm 46346c59934SDag-Erling Smørgrav mdate = "M([1-9]|1[0-2])\\.[1-5]\\.[0-6]" 46446c59934SDag-Erling Smørgrav jdate = ("((J[1-9]|[0-9]|J?[1-9][0-9]" \ 46546c59934SDag-Erling Smørgrav "|J?[1-2][0-9][0-9])|J?3[0-5][0-9]|J?36[0-5])") 46646c59934SDag-Erling Smørgrav datetime = ",(" mdate "|" jdate ")(/" time ")?" 46746c59934SDag-Erling Smørgrav tzpattern = ("^(:.*|" tzname offset "(" tzname \ 46846c59934SDag-Erling Smørgrav "(" offset ")?(" datetime datetime ")?)?)$") 46946c59934SDag-Erling Smørgrav exit tz ~ tzpattern 47046c59934SDag-Erling Smørgrav } 47146c59934SDag-Erling Smørgrav ' 47246c59934SDag-Erling Smørgrav 473bc421551SDag-Erling Smørgrav while 474bc421551SDag-Erling Smørgrav echo >&2 'Please enter the desired value' \ 475bc421551SDag-Erling Smørgrav 'of the TZ environment variable.' 476bc421551SDag-Erling Smørgrav echo >&2 'For example, AEST-10 is abbreviated' \ 477bc421551SDag-Erling Smørgrav 'AEST and is 10 hours' 478bc421551SDag-Erling Smørgrav echo >&2 'ahead (east) of Greenwich,' \ 479bc421551SDag-Erling Smørgrav 'with no daylight saving time.' 48046c59934SDag-Erling Smørgrav read tz 48146c59934SDag-Erling Smørgrav $AWK "$check_POSIX_TZ_string" ="$tz" 482bc421551SDag-Erling Smørgrav do 483*a979394aSDag-Erling Smørgrav say >&2 "'$tz' is not a conforming POSIX proleptic TZ string." 484bc421551SDag-Erling Smørgrav done 48546c59934SDag-Erling Smørgrav TZ_for_date=$tz;; 486bc421551SDag-Erling Smørgrav *) 487bc421551SDag-Erling Smørgrav case $continent in 488bc421551SDag-Erling Smørgrav coord) 489bc421551SDag-Erling Smørgrav case $coord in 490bc421551SDag-Erling Smørgrav '') 491bc421551SDag-Erling Smørgrav echo >&2 'Please enter coordinates' \ 492bc421551SDag-Erling Smørgrav 'in ISO 6709 notation.' 493bc421551SDag-Erling Smørgrav echo >&2 'For example, +4042-07403 stands for' 494bc421551SDag-Erling Smørgrav echo >&2 '40 degrees 42 minutes north,' \ 495bc421551SDag-Erling Smørgrav '74 degrees 3 minutes west.' 49646c59934SDag-Erling Smørgrav read coord 497bc421551SDag-Erling Smørgrav esac 498*a979394aSDag-Erling Smørgrav distance_table=$( 49946c59934SDag-Erling Smørgrav $AWK \ 50046c59934SDag-Erling Smørgrav "$output_distances_or_times" \ 50146c59934SDag-Erling Smørgrav ="$coord" ="$TZ_COUNTRY_TABLE" ="$TZ_ZONE_TABLE" | 502bc421551SDag-Erling Smørgrav sort -n | 50346c59934SDag-Erling Smørgrav $AWK "{print} NR == $location_limit { exit }" 504*a979394aSDag-Erling Smørgrav ) 505*a979394aSDag-Erling Smørgrav regions=$( 50646c59934SDag-Erling Smørgrav $AWK ' 50775411d15SDag-Erling Smørgrav BEGIN { 50846c59934SDag-Erling Smørgrav distance_table = substr(ARGV[1], 2) 50946c59934SDag-Erling Smørgrav ARGV[1] = "" 51075411d15SDag-Erling Smørgrav nlines = split(distance_table, line, /\n/) 51175411d15SDag-Erling Smørgrav for (nr = 1; nr <= nlines; nr++) { 51275411d15SDag-Erling Smørgrav nf = split(line[nr], f, /\t/) 51375411d15SDag-Erling Smørgrav print f[nf] 51475411d15SDag-Erling Smørgrav } 51575411d15SDag-Erling Smørgrav } 51646c59934SDag-Erling Smørgrav ' ="$distance_table" 517*a979394aSDag-Erling Smørgrav ) 51875411d15SDag-Erling Smørgrav echo >&2 'Please select one of the following timezones,' 519bc421551SDag-Erling Smørgrav echo >&2 'listed roughly in increasing order' \ 520bc421551SDag-Erling Smørgrav "of distance from $coord". 521bc421551SDag-Erling Smørgrav doselect $regions 522bc421551SDag-Erling Smørgrav region=$select_result 523*a979394aSDag-Erling Smørgrav tz=$( 52446c59934SDag-Erling Smørgrav $AWK ' 52575411d15SDag-Erling Smørgrav BEGIN { 52646c59934SDag-Erling Smørgrav distance_table = substr(ARGV[1], 2) 52746c59934SDag-Erling Smørgrav region = substr(ARGV[2], 2) 52846c59934SDag-Erling Smørgrav ARGV[1] = ARGV[2] = "" 52975411d15SDag-Erling Smørgrav nlines = split(distance_table, line, /\n/) 53075411d15SDag-Erling Smørgrav for (nr = 1; nr <= nlines; nr++) { 53175411d15SDag-Erling Smørgrav nf = split(line[nr], f, /\t/) 53246c59934SDag-Erling Smørgrav if (f[nf] == region) 53375411d15SDag-Erling Smørgrav print f[4] 53475411d15SDag-Erling Smørgrav } 53575411d15SDag-Erling Smørgrav } 53646c59934SDag-Erling Smørgrav ' ="$distance_table" ="$region" 537*a979394aSDag-Erling Smørgrav );; 538bc421551SDag-Erling Smørgrav *) 53975411d15SDag-Erling Smørgrav case $continent in 54046c59934SDag-Erling Smørgrav now|time) 54175411d15SDag-Erling Smørgrav minute_format='%a %b %d %H:%M' 542*a979394aSDag-Erling Smørgrav old_minute=$(TZ=UTC0 date +"$minute_format") 54375411d15SDag-Erling Smørgrav for i in 1 2 3 54475411d15SDag-Erling Smørgrav do 545*a979394aSDag-Erling Smørgrav time_table_command=$( 54646c59934SDag-Erling Smørgrav $AWK \ 54746c59934SDag-Erling Smørgrav -v output_times=1 \ 54846c59934SDag-Erling Smørgrav "$output_distances_or_times" \ 54946c59934SDag-Erling Smørgrav = = ="$TZ_ZONE_TABLE" 550*a979394aSDag-Erling Smørgrav ) 551*a979394aSDag-Erling Smørgrav time_table=$(eval "$time_table_command") 552*a979394aSDag-Erling Smørgrav new_minute=$(TZ=UTC0 date +"$minute_format") 55375411d15SDag-Erling Smørgrav case $old_minute in 55446c59934SDag-Erling Smørgrav "$new_minute") break 55575411d15SDag-Erling Smørgrav esac 55675411d15SDag-Erling Smørgrav old_minute=$new_minute 55775411d15SDag-Erling Smørgrav done 55875411d15SDag-Erling Smørgrav echo >&2 "The system says Universal Time is $new_minute." 55975411d15SDag-Erling Smørgrav echo >&2 "Assuming that's correct, what is the local time?" 560*a979394aSDag-Erling Smørgrav sorted_table=$(say "$time_table" | sort -k2n -k2,5 -k1n) || { 56146c59934SDag-Erling Smørgrav say >&2 "$0: cannot sort time table" 56246c59934SDag-Erling Smørgrav exit 1 56346c59934SDag-Erling Smørgrav } 564*a979394aSDag-Erling Smørgrav eval doselect $( 56546c59934SDag-Erling Smørgrav $AWK ' 56646c59934SDag-Erling Smørgrav BEGIN { 56746c59934SDag-Erling Smørgrav sorted_table = substr(ARGV[1], 2) 56846c59934SDag-Erling Smørgrav ARGV[1] = "" 56946c59934SDag-Erling Smørgrav nlines = split(sorted_table, line, /\n/) 57046c59934SDag-Erling Smørgrav for (i = 1; i <= nlines; i++) { 57146c59934SDag-Erling Smørgrav $0 = line[i] 57246c59934SDag-Erling Smørgrav outline = $6 " " $7 " " $4 " " $5 57346c59934SDag-Erling Smørgrav if (outline == oldline) 57446c59934SDag-Erling Smørgrav continue 57546c59934SDag-Erling Smørgrav oldline = outline 57646c59934SDag-Erling Smørgrav gsub(/'\''/, "&\\\\&&", outline) 57746c59934SDag-Erling Smørgrav printf "'\''%s'\''\n", outline 57846c59934SDag-Erling Smørgrav } 57946c59934SDag-Erling Smørgrav } 58046c59934SDag-Erling Smørgrav ' ="$sorted_table" 581*a979394aSDag-Erling Smørgrav ) 58275411d15SDag-Erling Smørgrav time=$select_result 58346c59934SDag-Erling Smørgrav continent_re='^' 584*a979394aSDag-Erling Smørgrav zone_table=$( 58546c59934SDag-Erling Smørgrav $AWK ' 58646c59934SDag-Erling Smørgrav BEGIN { 58746c59934SDag-Erling Smørgrav time = substr(ARGV[1], 2) 58846c59934SDag-Erling Smørgrav time_table = substr(ARGV[2], 2) 58946c59934SDag-Erling Smørgrav ARGV[1] = ARGV[2] = "" 59046c59934SDag-Erling Smørgrav nlines = split(time_table, line, /\n/) 59146c59934SDag-Erling Smørgrav for (i = 1; i <= nlines; i++) { 59246c59934SDag-Erling Smørgrav $0 = line[i] 59375411d15SDag-Erling Smørgrav if ($6 " " $7 " " $4 " " $5 == time) { 59475411d15SDag-Erling Smørgrav sub(/[^\t]*\t/, "") 59575411d15SDag-Erling Smørgrav print 59675411d15SDag-Erling Smørgrav } 59746c59934SDag-Erling Smørgrav } 59846c59934SDag-Erling Smørgrav } 59946c59934SDag-Erling Smørgrav ' ="$time" ="$time_table" 600*a979394aSDag-Erling Smørgrav ) 601*a979394aSDag-Erling Smørgrav countries=$( 60275411d15SDag-Erling Smørgrav $AWK \ 60346c59934SDag-Erling Smørgrav "$output_country_list" \ 60446c59934SDag-Erling Smørgrav ="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" | 60575411d15SDag-Erling Smørgrav sort -f 606*a979394aSDag-Erling Smørgrav ) 60775411d15SDag-Erling Smørgrav ;; 60875411d15SDag-Erling Smørgrav *) 60946c59934SDag-Erling Smørgrav continent_re="^$continent/" 61046c59934SDag-Erling Smørgrav zone_table=$TZ_ZONE_TABLE 61175411d15SDag-Erling Smørgrav esac 612bc421551SDag-Erling Smørgrav 61346c59934SDag-Erling Smørgrav # Get list of names of countries in the continent or ocean. 614*a979394aSDag-Erling Smørgrav countries=$( 61546c59934SDag-Erling Smørgrav $AWK \ 61646c59934SDag-Erling Smørgrav "$output_country_list" \ 61746c59934SDag-Erling Smørgrav ="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" | 61846c59934SDag-Erling Smørgrav sort -f 619*a979394aSDag-Erling Smørgrav ) 62046c59934SDag-Erling Smørgrav # If all zone table entries have comments, and there are 62146c59934SDag-Erling Smørgrav # at most 22 entries, asked based on those comments. 62246c59934SDag-Erling Smørgrav # This fits the prompt onto old-fashioned 24-line screens. 623*a979394aSDag-Erling Smørgrav regions=$( 62446c59934SDag-Erling Smørgrav $AWK ' 62546c59934SDag-Erling Smørgrav BEGIN { 62646c59934SDag-Erling Smørgrav TZ_ZONE_TABLE = substr(ARGV[1], 2) 62746c59934SDag-Erling Smørgrav ARGV[1] = "" 62846c59934SDag-Erling Smørgrav FS = "\t" 62946c59934SDag-Erling Smørgrav nlines = split(TZ_ZONE_TABLE, line, /\n/) 63046c59934SDag-Erling Smørgrav for (i = 1; i <= nlines; i++) { 63146c59934SDag-Erling Smørgrav $0 = line[i] 63246c59934SDag-Erling Smørgrav if ($0 ~ /^[^#]/ && !missing_comment) { 63346c59934SDag-Erling Smørgrav if ($4) 63446c59934SDag-Erling Smørgrav comment[++inlines] = $4 63546c59934SDag-Erling Smørgrav else 63646c59934SDag-Erling Smørgrav missing_comment = 1 63746c59934SDag-Erling Smørgrav } 63846c59934SDag-Erling Smørgrav } 63946c59934SDag-Erling Smørgrav if (!missing_comment && inlines <= 22) 64046c59934SDag-Erling Smørgrav for (i = 1; i <= inlines; i++) 64146c59934SDag-Erling Smørgrav print comment[i] 64246c59934SDag-Erling Smørgrav } 64346c59934SDag-Erling Smørgrav ' ="$zone_table" 644*a979394aSDag-Erling Smørgrav ) 64546c59934SDag-Erling Smørgrav 646bc421551SDag-Erling Smørgrav # If there's more than one country, ask the user which one. 647bc421551SDag-Erling Smørgrav case $countries in 648bc421551SDag-Erling Smørgrav *"$newline"*) 649bc421551SDag-Erling Smørgrav echo >&2 'Please select a country' \ 650bc421551SDag-Erling Smørgrav 'whose clocks agree with yours.' 651bc421551SDag-Erling Smørgrav doselect $countries 65275411d15SDag-Erling Smørgrav country_result=$select_result 653bc421551SDag-Erling Smørgrav country=$select_result;; 654bc421551SDag-Erling Smørgrav *) 655bc421551SDag-Erling Smørgrav country=$countries 656bc421551SDag-Erling Smørgrav esac 657bc421551SDag-Erling Smørgrav 658bc421551SDag-Erling Smørgrav 659bc421551SDag-Erling Smørgrav # Get list of timezones in the country. 660*a979394aSDag-Erling Smørgrav regions=$( 66146c59934SDag-Erling Smørgrav $AWK ' 662bc421551SDag-Erling Smørgrav BEGIN { 66346c59934SDag-Erling Smørgrav country = substr(ARGV[1], 2) 66446c59934SDag-Erling Smørgrav TZ_COUNTRY_TABLE = substr(ARGV[2], 2) 66546c59934SDag-Erling Smørgrav TZ_ZONE_TABLE = substr(ARGV[3], 2) 66646c59934SDag-Erling Smørgrav ARGV[1] = ARGV[2] = ARGV[3] = "" 667bc421551SDag-Erling Smørgrav FS = "\t" 668bc421551SDag-Erling Smørgrav cc = country 66946c59934SDag-Erling Smørgrav nlines = split(TZ_COUNTRY_TABLE, line, /\n/) 67046c59934SDag-Erling Smørgrav for (i = 1; i <= nlines; i++) { 67146c59934SDag-Erling Smørgrav $0 = line[i] 672bc421551SDag-Erling Smørgrav if ($0 !~ /^#/ && country == $2) { 673bc421551SDag-Erling Smørgrav cc = $1 674bc421551SDag-Erling Smørgrav break 675bc421551SDag-Erling Smørgrav } 676bc421551SDag-Erling Smørgrav } 67746c59934SDag-Erling Smørgrav nlines = split(TZ_ZONE_TABLE, line, /\n/) 67846c59934SDag-Erling Smørgrav for (i = 1; i <= nlines; i++) { 67946c59934SDag-Erling Smørgrav $0 = line[i] 68046c59934SDag-Erling Smørgrav if ($0 ~ /^#/) 68146c59934SDag-Erling Smørgrav continue 68246c59934SDag-Erling Smørgrav if ($1 ~ cc) 68346c59934SDag-Erling Smørgrav print $4 684bc421551SDag-Erling Smørgrav } 68546c59934SDag-Erling Smørgrav } 68646c59934SDag-Erling Smørgrav ' ="$country" ="$TZ_COUNTRY_TABLE" ="$zone_table" 687*a979394aSDag-Erling Smørgrav ) 688bc421551SDag-Erling Smørgrav 689bc421551SDag-Erling Smørgrav # If there's more than one region, ask the user which one. 690bc421551SDag-Erling Smørgrav case $regions in 691bc421551SDag-Erling Smørgrav *"$newline"*) 692bc421551SDag-Erling Smørgrav echo >&2 'Please select one of the following timezones.' 693bc421551SDag-Erling Smørgrav doselect $regions 69475411d15SDag-Erling Smørgrav region=$select_result 695bc421551SDag-Erling Smørgrav esac 696bc421551SDag-Erling Smørgrav 69746c59934SDag-Erling Smørgrav # Determine tz from country and region. 698*a979394aSDag-Erling Smørgrav tz=$( 69946c59934SDag-Erling Smørgrav $AWK ' 700bc421551SDag-Erling Smørgrav BEGIN { 70146c59934SDag-Erling Smørgrav country = substr(ARGV[1], 2) 70246c59934SDag-Erling Smørgrav region = substr(ARGV[2], 2) 70346c59934SDag-Erling Smørgrav TZ_COUNTRY_TABLE = substr(ARGV[3], 2) 70446c59934SDag-Erling Smørgrav TZ_ZONE_TABLE = substr(ARGV[4], 2) 70546c59934SDag-Erling Smørgrav ARGV[1] = ARGV[2] = ARGV[3] = ARGV[4] = "" 706bc421551SDag-Erling Smørgrav FS = "\t" 707bc421551SDag-Erling Smørgrav cc = country 70846c59934SDag-Erling Smørgrav nlines = split(TZ_COUNTRY_TABLE, line, /\n/) 70946c59934SDag-Erling Smørgrav for (i = 1; i <= nlines; i++) { 71046c59934SDag-Erling Smørgrav $0 = line[i] 711bc421551SDag-Erling Smørgrav if ($0 !~ /^#/ && country == $2) { 712bc421551SDag-Erling Smørgrav cc = $1 713bc421551SDag-Erling Smørgrav break 714bc421551SDag-Erling Smørgrav } 715bc421551SDag-Erling Smørgrav } 71646c59934SDag-Erling Smørgrav nlines = split(TZ_ZONE_TABLE, line, /\n/) 71746c59934SDag-Erling Smørgrav for (i = 1; i <= nlines; i++) { 71846c59934SDag-Erling Smørgrav $0 = line[i] 71946c59934SDag-Erling Smørgrav if ($0 ~ /^#/) 72046c59934SDag-Erling Smørgrav continue 72146c59934SDag-Erling Smørgrav if ($1 ~ cc && ($4 == region || !region)) 72246c59934SDag-Erling Smørgrav print $3 723bc421551SDag-Erling Smørgrav } 72446c59934SDag-Erling Smørgrav } 72546c59934SDag-Erling Smørgrav ' ="$country" ="$region" ="$TZ_COUNTRY_TABLE" ="$zone_table" 726*a979394aSDag-Erling Smørgrav ) 727bc421551SDag-Erling Smørgrav esac 728bc421551SDag-Erling Smørgrav 729bc421551SDag-Erling Smørgrav # Make sure the corresponding zoneinfo file exists. 73046c59934SDag-Erling Smørgrav TZ_for_date=$TZDIR/$tz 731bc421551SDag-Erling Smørgrav <"$TZ_for_date" || { 732bc421551SDag-Erling Smørgrav say >&2 "$0: time zone files are not set up correctly" 733bc421551SDag-Erling Smørgrav exit 1 734bc421551SDag-Erling Smørgrav } 735bc421551SDag-Erling Smørgrav esac 736bc421551SDag-Erling Smørgrav 737bc421551SDag-Erling Smørgrav 738bc421551SDag-Erling Smørgrav # Use the proposed TZ to output the current date relative to UTC. 739bc421551SDag-Erling Smørgrav # Loop until they agree in seconds. 740bc421551SDag-Erling Smørgrav # Give up after 8 unsuccessful tries. 741bc421551SDag-Erling Smørgrav 742bc421551SDag-Erling Smørgrav extra_info= 743bc421551SDag-Erling Smørgrav for i in 1 2 3 4 5 6 7 8 744bc421551SDag-Erling Smørgrav do 745*a979394aSDag-Erling Smørgrav TZdate=$(LANG=C TZ="$TZ_for_date" date) 746*a979394aSDag-Erling Smørgrav UTdate=$(LANG=C TZ=UTC0 date) 747*a979394aSDag-Erling Smørgrav TZsecsetc=${TZdate##*[0-5][0-9]:} 748*a979394aSDag-Erling Smørgrav UTsecsetc=${UTdate##*[0-5][0-9]:} 749*a979394aSDag-Erling Smørgrav if test "${TZsecsetc%%[!0-9]*}" = "${UTsecsetc%%[!0-9]*}" 75046c59934SDag-Erling Smørgrav then 751bc421551SDag-Erling Smørgrav extra_info=" 752bc421551SDag-Erling SmørgravSelected time is now: $TZdate. 753bc421551SDag-Erling SmørgravUniversal Time is now: $UTdate." 754bc421551SDag-Erling Smørgrav break 75546c59934SDag-Erling Smørgrav fi 756bc421551SDag-Erling Smørgrav done 757bc421551SDag-Erling Smørgrav 758bc421551SDag-Erling Smørgrav 759bc421551SDag-Erling Smørgrav # Output TZ info and ask the user to confirm. 760bc421551SDag-Erling Smørgrav 761bc421551SDag-Erling Smørgrav echo >&2 "" 76275411d15SDag-Erling Smørgrav echo >&2 "Based on the following information:" 763bc421551SDag-Erling Smørgrav echo >&2 "" 76475411d15SDag-Erling Smørgrav case $time%$country_result%$region%$coord in 76575411d15SDag-Erling Smørgrav ?*%?*%?*%) 76675411d15SDag-Erling Smørgrav say >&2 " $time$newline $country_result$newline $region";; 76775411d15SDag-Erling Smørgrav ?*%?*%%|?*%%?*%) say >&2 " $time$newline $country_result$region";; 76875411d15SDag-Erling Smørgrav ?*%%%) say >&2 " $time";; 76975411d15SDag-Erling Smørgrav %?*%?*%) say >&2 " $country_result$newline $region";; 77075411d15SDag-Erling Smørgrav %?*%%) say >&2 " $country_result";; 77175411d15SDag-Erling Smørgrav %%?*%?*) say >&2 " coord $coord$newline $region";; 77275411d15SDag-Erling Smørgrav %%%?*) say >&2 " coord $coord";; 77346c59934SDag-Erling Smørgrav *) say >&2 " TZ='$tz'" 774bc421551SDag-Erling Smørgrav esac 775bc421551SDag-Erling Smørgrav say >&2 "" 77646c59934SDag-Erling Smørgrav say >&2 "TZ='$tz' will be used.$extra_info" 777bc421551SDag-Erling Smørgrav say >&2 "Is the above information OK?" 778bc421551SDag-Erling Smørgrav 779bc421551SDag-Erling Smørgrav doselect Yes No 780bc421551SDag-Erling Smørgrav ok=$select_result 781bc421551SDag-Erling Smørgrav case $ok in 782bc421551SDag-Erling Smørgrav Yes) break 783bc421551SDag-Erling Smørgrav esac 784bc421551SDag-Erling Smørgravdo coord= 785bc421551SDag-Erling Smørgravdone 786bc421551SDag-Erling Smørgrav 787bc421551SDag-Erling Smørgravcase $SHELL in 78846c59934SDag-Erling Smørgrav*csh) file=.login line="setenv TZ '$tz'";; 789*a979394aSDag-Erling Smørgrav*) file=.profile line="export TZ='$tz'" 790bc421551SDag-Erling Smørgravesac 791bc421551SDag-Erling Smørgrav 792bc421551SDag-Erling Smørgravtest -t 1 && say >&2 " 793bc421551SDag-Erling SmørgravYou can make this change permanent for yourself by appending the line 794bc421551SDag-Erling Smørgrav $line 795bc421551SDag-Erling Smørgravto the file '$file' in your home directory; then log out and log in again. 796bc421551SDag-Erling Smørgrav 797bc421551SDag-Erling SmørgravHere is that TZ value again, this time on standard output so that you 798bc421551SDag-Erling Smørgravcan use the $0 command in shell scripts:" 799bc421551SDag-Erling Smørgrav 80046c59934SDag-Erling Smørgravsay "$tz" 801