Ted Byers wrote:
I am presently looking at a few perl packages that should facilitate
developing such a package (which I will do in due course if no-one
identifies one that already exists - I haven't found one).
Existing Geo and DateTime Perl modules will do what you said you needed
done: look up time zones by city names and then use those time zones in
date and time computations. There's no need to write a new module.
The packages I am looking at are:
Geo::GeoNames
Geo::GeoNames::File
Geo::Query::LatLong
Geo::Location::TimeZone
I figure the first two provide for two different ways to use the geonames
data. The first uses the geoNames web services (and requires you to sign
up for an account - I do not know how long that will continue to be
available without cost), and the second provides a way to use the same data
from one of their data files that you have downloaded to your own system.
I see the second two being a fallback solution if the city in question is
not in the geonames database. Geo::Query::LatLong lets you get the
latitude and longitude of a city and Geo::Location::TimeZone gives you the
timezone for a given position sepcified by latitude and longitude. This
strikes me as more sensible, and almost certainly faster, than trying to
find the city in the oslen db that is closest to the city for which you
want the timezone.
The overall logic would be to first see if the city for which you want a
timezone is in the Olson DB. If not, check geonames, and if that fails,
use the latitude and longitude of the city to get a timezone.
The Olson tz database (now, properly, the IANA Time Zone Database) is a
database of time zones, not a database of cities. The uniform convention
designed by Paul Eggert to name time zones in the database typically
includes the name of a representative city within the region defined by
the time zone. So which city within the region is used in the name of the
time zone? The Wikipedia article titled "tz database" explains:
Usually the most populous city in a region is chosen to represent the
entire time zone, although other cities may be selected if they are
more widely known or result in a less ambiguous name. ... The location
selected is representative for the entire area.
http://en.wikipedia.org/wiki/Tz_database#LocationYitzchak Scott-Thoennes explained this in a reply to your datetime mailing
list inquiry about this same topic in August 2009. He wrote:
Within each zone, the most "recognizable" city is used as the name.
In some cases, this isn't the largest. See the comments in the region
files for rationales.
http://www.nntp.perl.org/group/perl.datetime/2009/08/msg7333.htmlI am also looking at loading the GeoNames data into my databases
(Postgresql and MySQL), and accessing that directly instead of accessing
it from a text file: this would be to determine which is faster.
Consider SQLite. There's an existing module named Geo::GeoNames::DB::SQLite.
One of the tasks I suppose I will have to do is check to see how many of
the time zones in these other sources are incompatible with those in the
Olson DB, and then find a mapping of them to the Olson timezones.
All you need to determine which time zone a city is in is a database of
of time zones by location. The GeoNames geographical database is just such
a database. It uses the Olson tz database time zones and time zone names.
There are no "incompatible" time zones in the GeoNames database.
I wrote a small proof-of-concept Perl script using Geo::GeoNames and
DateTime to demonstrate how to look up time zones by city names and then
use those time zones to instantiate DateTime objects.
--------------------------------------------------------------------------
C:\Demo>cat now.pl
#!perl
use strict;
use warnings;
use DateTime;
use Geo::GeoNames;
use URI::Escape;
binmode STDOUT, ':encoding(UTF-8)';
my $city = @ARGV ? shift : 'Tempe';
my $geo = Geo::GeoNames->new( username => '*********' );
my $result = $geo->search(
q => uri_escape_utf8($city),
maxRows => 1,
style => 'FULL'
);
defined $result->[0] or die "Unrecognized city '$city'\n";
my $city_name = $result->[0]->{name};
my $country_name = $result->[0]->{countryName};
my $time_zone = $result->[0]->{timezone}{content};
my $time_now = DateTime->now( time_zone => $time_zone );
print "$city_name ($country_name) $time_now ($time_zone)\n";
exit 0;
C:\Demo>now
Tempe (United States) 2012-08-18T20:47:15 (America/Phoenix)
C:\Demo>now Flagstaff
Flagstaff (United States) 2012-08-18T20:47:20 (America/Phoenix)
C:\Demo>now "Window Rock"
Window Rock (United States) 2012-08-18T21:47:26 (America/Shiprock)
C:\Demo>now "Salt Lake City"
Salt Lake City (United States) 2012-08-18T21:47:34 (America/Denver)
C:\Demo>now "New York"
New York (United States) 2012-08-18T23:47:42 (America/New_York)
C:\Demo>now "Washington D.C."
Washington (United States) 2012-08-18T23:47:52 (America/New_York)
C:\Demo>now Saratoga
Saratoga Springs (United States) 2012-08-18T23:48:15 (America/New_York)
C:\Demo>now Baden-Württemberg
Baden-Baden (Germany) 2012-08-19T05:49:11 (Europe/Berlin)
C:\Demo>now Yūbari | cat -Uc8pa
Yūbari-shi (Japan) 2012-08-19T12:50:41 (Asia/Tokyo)
C:\Demo>now Bombay
Mumbai (India) 2012-08-19T09:21:11 (Asia/Kolkata)
C:\Demo>now Calcutta
Kolkata (India) 2012-08-19T09:21:19 (Asia/Kolkata)
C:\Demo>now "New Delhi"
New Delhi (India) 2012-08-19T09:21:29 (Asia/Kolkata)
C:\Demo>now Timbuktu
Timbuktu (Mali) 2012-08-19T03:51:49 (Africa/Bamako)
C:\Demo>now "Lake Chaubunagungamaug"
Lake Chaubunagungamaug (United States) 2012-08-18T23:52:34 (America/New_York)
C:\Demo>now Chargoggagoggmanchauggagoggchaubunagungamaugg
Unrecognized city 'Chargoggagoggmanchauggagoggchaubunagungamaugg'
C:\Demo>
--------------------------------------------------------------------------
Arizona is in the U.S. Mountain Time Zone, but Arizona doesn't observe
daylight saving time. So Tempe and Flagstaff are in the 'America/Phoenix'
time zone, not the 'America/Denver' time zone.
Window Rock is in Arizona, but it's also in the Navajo Nation. Unlike the
rest of Arizona, the Navajo Nation observes daylight saving time. So
Window Rock is in the 'America/Shiprock' time zone. As it happens,
Shiprock, a representative location in the Navajo Nation, is in New Mexico,
not in Arizona.
Salt Lake City is a big, well-known city that, like Phoenix, is in the
U.S. Mountain Time Zone. But Utah observes daylight saving time, so Salt
Lake City is in the 'America/Denver' time zone.
When you look up Bombay in the GeoNames geographical database, you get
Mumbai. When you look up Calcutta, you get Kolkata. When you look up
New Delhi, you get New Delhi. All of these cities in India are in the
'Asia/Kolkata' time zone.
Jim Monty