in the trenches. Here in Houston, Texas, in the April 15th issue of our local alternative newspaper the
I knew this couldn't be right since I was aware of at least a couple of time zones with half-hour offsets, plus even one with a 45 minute offset (Nepal). So I whipped up a quick script using DateTime and DateTime::TimeZone, which is based on the Olson Timezone Database, to find out how many time zones for which these requirements might apply. I made a rudimentary attempt at including DST effects by running all calculations twice -- once for Jan 1 and once for Aug 1.
The summary: There are 12 zones, potentially, with half-hour offsets. There are two with 45 minute offsets. There are 160 possible zones for being 5pm when it is 12:30pm somewhere else, out of 367 total.
Time on My Hands
In the April 15, 2004 "Day by Day" picks Keith Plocek rags on the lyrics
for the song "It's Five O'Clock Somewhere" by Jimmy Buffett and Alan
Jackson, saying "it doesn't take a genius to know that it can't be 5
p.m. anywhere when it's 12:30 p.m. somewhere else."
Consulting the Olson timezone database, including possible DST effects,
it turns out that there are twelve time zones with offsets landing on
the half hour. Further calculations relative to those zones reveal 160
candidates out of 367 possible time zones for an offset such as the
song suggests.
The next time I'm in Los Angeles in the winter, for example, I can enjoy
a 12:30 toast to Jimmy Buffett down in St. Johns where he will no doubt
be enjoying his favorite frozen concoction. Jimmy, on the other hand,
will have to content himself with a lunchtime toast towards somewhere
such as Budapest.
For the record, the twelve zones that enjoy half-hour offsets are:
America/St_Johns, Asia/Calcutta, Asia/Kabul, Asia/Rangoon, Asia/Tehran,
Australia/Adelaide, Australia/Broken_Hill, Australia/Darwin,
Australia/Lord_Howe, Indian/Cocos, Pacific/Marquesas, and
Pacific/Norfolk. Things are further complicated by Asia/Katmandu and
Pacific/Chatham, which have 45 minute offsets.
Cheers,
Matt Sisk
April 28, 2004
#!/usr/bin/perl
#
# author: Matt Sisk, April 2004
# no rights reserved -- do what you want with this
use strict;
use warnings;
use DateTime;
use DateTime::TimeZone;
my %jan_parm = ( year => 2004, month => 1, day => 1);
my %aug_parm = ( year => 2004, month => 7, day => 1);
my %jan = run_zones(%jan_parm);
my %aug = run_zones(%aug_parm);
print "Jan (", scalar keys %jan, " zones):\n";
print_zones(\%jan);
print "\nAug (", scalar keys %aug, " zones sans jan):\n";
my %notjan;
$notjan{$_} = $aug{$_} foreach grep(!$jan{$_}, keys %aug);
print_zones(\%notjan);
my @znames = DateTime::TimeZone::all_names;
my $j5 = find_5_from_12_30(\%jan_parm, [keys %jan], \@znames);
my $a5 = find_5_from_12_30(\%aug_parm, [keys %aug], \@znames);
my $jj5 = find_5_from_12_30(\%jan_parm, \@znames, [keys %jan]);
my $aa5 = find_5_from_12_30(\%aug_parm, \@znames, [keys %aug]);
print_one2many($j5, '2004/01/01 12:30 => 17:00');
print_one2many($a5, '2004/07/01 12:30 => 17:00');
print_many2one($jj5, '2004/01/01 12:30 => 17:00');
print_many2one($aa5, '2004/07/01 12:30 => 17:00');
print '-' x 72, "\n";
printf "%3d for %s %5s -> %s\n", scalar keys %$j5, 'Jan', 'other', '
+odd';
printf "%3d for %s %5s -> %s\n", scalar keys %$a5, 'Aug', 'other', '
+odd';
printf "%3d for %s %5s -> %s\n", scalar keys %$jj5, 'Jan', 'odd', '
+other';
printf "%3d for %s %5s -> %s\n", scalar keys %$aa5, 'Aug', 'odd', '
+other';
my %tot;
foreach my $h ($j5, $a5, $jj5, $aa5) {
foreach (keys %$h) {
foreach (keys %{$h->{$_}}) {
++$tot{$_};
}
}
}
print scalar keys %tot, " hits total out of ",
scalar @znames, " possibilities.\n";
printf("%.2f%% hit ratio\n", 100*((scalar keys %tot)/(scalar @znames))
+);
exit;
###
sub run_zones {
my %parms = @_;
my %zones;
foreach my $name (DateTime::TimeZone::all_names) {
my $dt = DateTime->new(%parms, time_zone => $name);
next unless $dt->offset % 3600;
$zones{$name} = $dt->offset;
}
%zones;
}
sub find_5_from_12_30 {
my($mparms, $basis, $inspects) = @_;
my %found;
foreach (@$basis) {
my $dt = DateTime->new(
%$mparms,
hour => 12,
minute => 30,
time_zone => $_,
);
find_5_from_dt($dt, $inspects, \%found);
}
\%found;
}
sub find_5_from_dt {
my($dt, $inspects, $hits) = @_;
foreach my $name (@$inspects) {
my $c = $dt->clone;
$c->set_time_zone($name);
if ($c->hour == 17 && $c->minute == 0) {
++$hits->{$dt->time_zone->name}{$name};
}
}
}
sub print_zones {
my $h = shift;
my $len = 0;
foreach (keys %$h) {
$len = length if length > $len;
}
foreach (sort keys %$h) {
printf "%${len}s %3d:%02d\n", $_, int($h->{$_}/3600),
int(($h->{$_}%3600)/60);
}
}
sub print_many2one {
my($h, $label) = @_;
print "\n$label\n", '-' x 72, "\n";
my $len = 0;
foreach (keys %$h) {
$len = length if length > $len;
}
foreach (sort keys %$h) {
printf "%${len}s => %s\n", $_, join(', ', sort keys %{$h->{$_}});
}
}
sub print_one2many {
my($h, $label) = @_;
print "\n$label\n", '-' x 72, "\n";
my $len = 0;
foreach (keys %$h) {
$len = length if length > $len;
}
foreach (sort keys %$h) {
printf("%${len}s =>\n", $_);
foreach (sort keys %{$h->{$_}}) {
printf "%${len}s %s\n", ' ', $_;
}
}
}