http://qs1969.pair.com?node_id=348977

I thought I'd share with you a story of DateTime in the trenches. Here in Houston, Texas, in the April 15th issue of our local alternative newspaper the Houston Press they discuss the lyrics of the song "It's Five O'Clock Somewhere" by Jimmy Buffett and Alan Jackson.

In their discussion, they make the following statement:

Pardon us for being nitpicky, but we have some issues with Jimmy Buffett and Alan Jackson's song, "It's Five O'Clock Somewhere." Sure, we get the gist, but the whole concept really belies a complete ignorance of how time zones work. Just in case you haven't heard the song, here's the chorus in question: "Pour me something tall and strong / Make it a hurricane, before I go insane / It's only half past twelve, but I don't care / It's five o'clock somewhere." Apparently Mr. Buffett and Mr. Jackson haven't wandered very far from Margaritaville, 'cause 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.

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.

I've included the script and the letter I sent to the Houston Press. I've no idea if they'll print any of the letter since I didn't get around to checking the facts until recently, but they might.

Cheers!
Matt

Update: They published my letter, with minor modifications, in the May 13th, 2004 issue.


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", ' ', $_; } } }
edit (broquaint): added a <readmore>