diff --git a/tzselect.8 b/tzselect.8 index b5e2c88..884af36 100644 --- a/tzselect.8 +++ b/tzselect.8 @@ -4,6 +4,12 @@ tzselect \- select a time zone .SH SYNOPSIS .B tzselect [ +.B \-c +.I coord +] [ +.B \-n +.I limit +] [ .B \-t .I zonetabtype ] [ @@ -21,6 +27,26 @@ The output is suitable as a value for the TZ environment variable. All interaction with the user is done via standard input and standard error. .SH OPTIONS .TP +.BI "\-c " coord +Instead of asking for continent and then country and then city, +ask for selection from time zones whose largest cities +are closest to the location with geographical coordinates +.IR coord . +Use ISO 6709 notation for +.IR coord , +for example, +.B "\-c\ \+42.391415\-071.570419" +for 42.391415\(de\|N, 71.570419\(de\|W, and +.B "\-c\ +404226\-0740319" +for 48\(de\|42\(fm\|26\(sd\|N, 74\(de\|3\(fm\|19\(sd\|W. +.TP +.BI "\-n " limit +When +.B \-c +is used, display the closest +.I limit +locations (default 10). +.TP .BI "\-t " zonetabtype Make selections from the time zone table of type .IR zonetabtype . diff --git a/tzselect.ksh b/tzselect.ksh index dc9f256..da6adb2 100644 --- a/tzselect.ksh +++ b/tzselect.ksh @@ -1,5 +1,7 @@ #!/bin/bash +export LC_ALL=C + PKGVERSION='(tzcode) ' TZVERSION=see_Makefile REPORT_BUGS_TO=tz@iana.org @@ -41,15 +43,43 @@ ZONETABTYPE=zone exit 1 } -usage="Usage: tzselect [--version] [--help] [-t ZONETABTYPE] +coord= +location_limit=10 + +usage="Usage: tzselect [--version] [--help] [-c COORD] [-n LIMIT] [-t ZONETABTYPE] Select a time zone interactively. -ZONETABTYPE should be one of 'time' or 'zone'. + +Options: + + -c COORD + Instead of asking for continent and then country and then city, + ask for selection from time zones whose largest cities + are closest to the location with geographical coordinates COORD. + COORD should use ISO 6709 notation, for example, '-c +4852+00220' + for Paris. + + -n LIMIT + Display at most LIMIT locations when -c is used (default $location_limit). + + -t ZONETABTYPE + Use time zone table ZONETABTYPE. ZONETABTYPE should be one of + 'time' or 'zone'. + + --version + Output version information. + + --help + Output this help. Report bugs to $REPORT_BUGS_TO." -while getopts t:-: opt +while getopts c:n:t:-: opt do case $opt$OPTARG in + c*) + coord=$OPTARG ;; + n*) + location_limit=$OPTARG ;; t*) ZONETABTYPE=$OPTARG ;; -help) @@ -90,6 +120,66 @@ case $(echo 1 | (select x in x; do break; done) 2>/dev/null) in ?*) PS3= esac +# Awk script to read a time zone table and output the same table, +# with each column preceded by its distance from 'here'. +output_distances=' + BEGIN { + FS = "\t" + while (getline &2 'Please select a continent or ocean.' + echo >&2 'Please select a continent, ocean, "coord", or "TZ".' select continent in \ Africa \ @@ -117,7 +211,8 @@ while Europe \ 'Indian Ocean' \ 'Pacific Ocean' \ - 'none - I want to specify the time zone using the Posix TZ format.' + 'coord - I want to use geographical coordinates.' \ + 'TZ - I want to specify the time zone using the Posix TZ format.' do case $continent in '') @@ -130,10 +225,12 @@ while break esac done + esac + case $continent in '') exit 1;; - none) + TZ) # Ask the user for a Posix TZ string. Check that it conforms. while echo >&2 'Please enter the desired value' \ @@ -158,6 +255,45 @@ while done TZ_for_date=$TZ;; *) + case $continent in + coord) + case $coord in + '') + echo >&2 'Please enter coordinates' \ + 'in ISO 6709 notation.' + echo >&2 'For example, +4042-07403 stands for' + echo >&2 '40 degrees 42 minutes north,' \ + '74 degrees 3 minutes west.' + read coord;; + esac + distance_table=$($AWK \ + -v coord="$coord" \ + -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ + "$output_distances" <$TZ_ZONE_TABLE | + sort -n | + sed "${location_limit}q" + ) + regions=$(echo "$distance_table" | $AWK ' + BEGIN { FS = "\t" } + { print $NF } + ') + echo >&2 'Please select one of the following' \ + 'time zone regions,' + echo >&2 'listed roughly in increasing order' \ + "of distance from $coord". + select region in $regions + do + case $region in + '') echo >&2 'Please enter a number in range.';; + ?*) break;; + esac + done + TZ=$(echo "$distance_table" | $AWK -v region="$region" ' + BEGIN { FS="\t" } + $NF == region { print $4 } + ') + ;; + *) # Get list of names of countries in the continent or ocean. countries=$($AWK -F'\t' \ -v continent="$continent" \ @@ -185,7 +321,8 @@ while # If there's more than one country, ask the user which one. case $countries in *"$newline"*) - echo >&2 'Please select a country.' + echo >&2 'Please select a country' \ + 'whose clocks agree with yours.' select country in $countries do case $country in @@ -256,6 +393,7 @@ while } $1 == cc && $4 == region { print $3 } ' <$TZ_ZONE_TABLE) + esac # Make sure the corresponding zoneinfo file exists. TZ_for_date=$TZDIR/$TZ @@ -292,9 +430,11 @@ Universal Time is now: $UTdate." echo >&2 "" echo >&2 "The following information has been given:" echo >&2 "" - case $country+$region in - ?*+?*) echo >&2 " $country$newline $region";; - ?*+) echo >&2 " $country";; + case $country%$region%$coord in + ?*%?*%) echo >&2 " $country$newline $region";; + ?*%%) echo >&2 " $country";; + %?*%?*) echo >&2 " coord $coord$newline $region";; + %%?*) echo >&2 " coord $coord";; +) echo >&2 " TZ='$TZ'" esac echo >&2 "" @@ -313,7 +453,7 @@ Universal Time is now: $UTdate." '') exit 1;; Yes) break esac -do : +do coord= done case $SHELL in