[tz] [PATCH] New file time.tab, superseding zone.tab

Paul Eggert eggert at cs.ucla.edu
Tue Aug 12 01:51:33 UTC 2014


Paul Eggert wrote:

> Perhaps a weighted
> sum of the distance and the square of the longitude difference, or
> something like that.

The attached patches, which I've pushed to the experimental repository, 
implement this suggestion with the simple weighting factor of 1.  The 
first patch is merely a typo fix.  On your test this patch causes the 
correct answer to be #8 out of 10, which is what it was in 2014e.  Of 
course the new heuristic is not perfect either....
-------------- next part --------------
diff --git a/tzselect.ksh b/tzselect.ksh
index 04762b4..c93d668 100644
--- a/tzselect.ksh
+++ b/tzselect.ksh
@@ -140,7 +140,7 @@ else
   }
 fi
 
-while getopts c:n:-: opt
+while getopts c:n:t:-: opt
 do
     case $opt$OPTARG in
     c*)
-------------- next part --------------
diff --git a/NEWS b/NEWS
index ce1612a..28902c9 100644
--- a/NEWS
+++ b/NEWS
@@ -19,6 +19,11 @@ Unreleased, experimental changes
 
     Asia/Dakha ended DST on 2009-12-31 at 24:00, not 23:59.
 
+  Changes affecting code
+
+    tzselect -c now uses a hybrid distance measure that works better
+    in Africa.  (Thanks to Alan Barrett for noting the problem.)
+
   Changes affecting distribution tarballs
 
     The files checktab.awk and zoneinfo2tdf.pl are now distributed in
diff --git a/tzselect.ksh b/tzselect.ksh
index c93d668..029abcd 100644
--- a/tzselect.ksh
+++ b/tzselect.ksh
@@ -192,7 +192,13 @@ output_distances='
         country[$1] = $2
     country["US"] = "US" # Otherwise the strings get too long.
   }
-  function convert_coord(coord, deg, min, ilen, sign, sec) {
+  function abs(x) {
+    return x < 0 ? -x : x;
+  }
+  function min(x, y) {
+    return x < y ? x : y;
+  }
+  function convert_coord(coord, deg, minute, ilen, sign, sec) {
     if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9][0-9][0-9]([^0-9]|$)/) {
       degminsec = coord
       intdeg = degminsec < 0 ? -int(-degminsec / 10000) : int(degminsec / 10000)
@@ -203,8 +209,8 @@ output_distances='
     } else if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9]([^0-9]|$)/) {
       degmin = coord
       intdeg = degmin < 0 ? -int(-degmin / 100) : int(degmin / 100)
-      min = degmin - intdeg * 100
-      deg = (intdeg * 60 + min) / 60
+      minute = degmin - intdeg * 100
+      deg = (intdeg * 60 + minute) / 60
     } else
       deg = coord
     return deg * 0.017453292519943296
@@ -220,7 +226,7 @@ output_distances='
   # Great-circle distance between points with given latitude and longitude.
   # Inputs and output are in radians.  This uses the great-circle special
   # case of the Vicenty formula for distances on ellipsoids.
-  function dist(lat1, long1, lat2, long2, dlong, x, y, num, denom) {
+  function gcdist(lat1, long1, lat2, long2, dlong, x, y, num, denom) {
     dlong = long2 - long1
     x = cos (lat2) * sin (dlong)
     y = cos (lat1) * sin (lat2) - sin (lat1) * cos (lat2) * cos (dlong)
@@ -228,6 +234,19 @@ output_distances='
     denom = sin (lat1) * sin (lat2) + cos (lat1) * cos (lat2) * cos (dlong)
     return atan2(num, denom)
   }
+  # Parallel distance between points with given latitude and longitude.
+  # This is the product of the longitude difference and the cosine
+  # of the latitude of the point that is further from the equator.
+  # I.e., it considers longitudes to be further apart if they are
+  # nearer the equator.
+  function pardist(lat1, long1, lat2, long2) {
+    return abs (long1 - long2) * min (cos (lat1), cos (lat2))
+  }
+  # The distance function is the sum of the great-circle distance and
+  # the parallel distance.  It could be weighted.
+  function dist(lat1, long1, lat2, long2) {
+    return gcdist (lat1, long1, lat2, long2) + pardist (lat1, long1, lat2, long2)
+  }
   BEGIN {
     coord_lat = convert_latitude(coord)
     coord_long = convert_longitude(coord)


More information about the tz mailing list