Re: Olson querying
Magic! Cheers! Rick Measham 📱 On 09/05/2012, at 6:38, mer...@stonehenge.com (Randal L. Schwartz) wrote: >> "Rick" == Rick Measham writes: > > Rick> $ olson time 13:48 # where is it currently 13:44? > Rick> $ olson time 13:48 -Cau # where in Australia is it currently 13:44 > > Does it offset by 4 minutes automatically? > > :-) > > -- > Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 > http://www.stonehenge.com/merlyn/> > Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc. > See http://methodsandmessages.posterous.com/ for Smalltalk discussion > -- > Message protected for iSite by MailGuard: e-mail anti-virus, anti-spam and > content filtering.http://www.mailguard.com.au > Click here to report this message as spam: > https://login.mailguard.com.au/report/1EHdSoFRAS/5NsrA9R5r7L6i9em677WM1/0 > -- Message protected for iSite by MailGuard: e-mail anti-virus, anti-spam and content filtering.http://www.mailguard.com.au
Re: Olson querying
> "Rick" == Rick Measham writes: Rick> $ olson time 13:48 # where is it currently 13:44? Rick> $ olson time 13:48 -Cau # where in Australia is it currently 13:44 Does it offset by 4 minutes automatically? :-) -- Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 http://www.stonehenge.com/merlyn/> Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc. See http://methodsandmessages.posterous.com/ for Smalltalk discussion
Re: Olson querying
Anthony Ball wrote: >a way to query when the DST changes happen. That'll need additions to the API for the timezone objects. I've got some plans to do that, but it's a later stage. -zefram
Re: Olson querying
Nice utility. I wouldn't mind something like this too: $ olson time 13:48 # where is it currently 13:44? $ olson time 13:48 -Cau # where in Australia is it currently 13:44 Australia/Currie Australia/Hobart Australia/Lindeman Australia/Melbourne Australia/Sydney Feels like a useful way to offer a limited number of zones to a customer when you know their localtime (eg. in a web interface) Cheers! Rick Measham On 6/03/2012 9:21 AM, Zefram wrote: New version of the query tool attached. This one has a lot more options for searching for zones. It lets you ask questions like: $ olson areas -Cru # where is Russia? Asia Europe $ olson offsets -ICST # what does "CST" mean? -06 -05 +08 +09:30 +10:30 $ olson zones -Cau -IEST # which zone might EST be in Australia? Australia/Brisbane Australia/Currie Australia/Hobart Australia/Lindeman Australia/Melbourne Australia/Sydney I've got a todo list with a bunch more features that it ought to support searching on, but I think I'm going to handle them by a radical refactoring that yields more of a query language than this collection of options. -zefram smime.p7s Description: S/MIME Cryptographic Signature
Re: Olson querying
New version of the query tool attached. This one has a lot more options for searching for zones. It lets you ask questions like: $ olson areas -Cru # where is Russia? Asia Europe $ olson offsets -ICST # what does "CST" mean? -06 -05 +08 +09:30 +10:30 $ olson zones -Cau -IEST # which zone might EST be in Australia? Australia/Brisbane Australia/Currie Australia/Hobart Australia/Lindeman Australia/Melbourne Australia/Sydney I've got a todo list with a bunch more features that it ought to support searching on, but I think I'm going to handle them by a radical refactoring that yields more of a query language than this collection of options. -zefram #!perl { use 5.006; } use warnings; use strict; use Date::ISO8601 0.000 qw(present_ymd); use DateTime::TimeZone::Olson (); use DateTime::TimeZone::SystemV (); use DateTime::TimeZone::Tzfile (); use Getopt::Std qw(getopts); use Params::Classify qw(is_string); use Time::OlsonTZ::Data (); use Time::Unix qw(time); our $VERSION = "0.000"; my $rdn_epoch_cjdn = 1721425; my %command; $command{version} = sub () { getopts("", {}) or die "bad options\n"; die "bad arguments\n" if @ARGV; print "modules:\nApp::olson $VERSION\n"; foreach my $mod (qw( DateTime::TimeZone::Olson DateTime::TimeZone::SystemV DateTime::TimeZone::Tzfile Time::OlsonTZ::Data )) { no strict "refs"; print "$mod ${qq(${mod}::VERSION)}\n"; } print "Olson database: @{[DateTime::TimeZone::Olson::olson_version]}\n"; }; { package FakeUtcDateTime; sub new { my($class, $rdns) = @_; return bless({ rdn => $rdns->[0], sod => $rdns->[1] }, $class); } sub utc_rd_values { ($_[0]->{rdn}, $_[0]->{sod}, 0) } } { package FakeLocalDateTime; sub new { my($class, $rdns) = @_; return bless({ rdn => $rdns->[0], sod => $rdns->[1] }, $class); } sub local_rd_values { ($_[0]->{rdn}, $_[0]->{sod}, 0) } } sub handle_exception($$) { my($val, $err) = @_; if($err =~ /\A time\ [-:TZ0-9]+\ is\ not\ represented\ in\ the\ [!-~]+ \ timezone\ due\ to\ (zone\ disuse|)\b /x) { return $1 eq "zone disuse" ? "!" : "?"; } elsif($err ne "") { return "*"; } else { return $val; } } sub is_exception($) { return is_string($_[0]) && $_[0] =~ /\A[!?*]\z/; } sub rdns_offset($$) { my($rdns, $offset) = @_; return $rdns if is_exception($rdns); return $offset if is_exception($offset); my($rdn, $sod) = @$rdns; $sod += $offset; use integer; my $doff = $sod < 0 ? -((86399-$sod) / 86400) : $sod / 86400; $rdn += $doff; $sod -= 86400*$doff; return [$rdn, $sod]; } sub present_rdns($) { my($rdns) = @_; return $rdns x 19 if is_exception($rdns); my($rdn, $sod) = @$rdns; use integer; return present_ymd($rdn + $rdn_epoch_cjdn). "T".sprintf("%02d:%02d:%02d", $sod/3600, $sod/60%60, $sod%60); } sub now_utc_dt() { my $now_unixtime = time; my $now_utc_rdn = 719163 + int($now_unixtime/86400); my $now_utc_sod = $now_unixtime % 86400; return FakeUtcDateTime->new([$now_utc_rdn, $now_utc_sod]); } my $current_utc_dt = now_utc_dt(); sub utc_to_local_dt($$) { my($utcdt, $offset) = @_; return $utcdt if is_exception($utcdt); return $offset if is_exception($offset); return FakeLocalDateTime->new( rdns_offset([$utcdt->utc_rd_values], $offset)); } sub local_to_utc_dt($$) { my($lcldt, $offset) = @_; return $lcldt if is_exception($lcldt); return $offset if is_exception($offset); return FakeUtcDateTime->new( rdns_offset([$lcldt->utc_rd_values], -$offset)); } sub present_utc_dt($) { my($dt) = @_; return present_rdns(is_exception($dt) ? $dt : [$dt->utc_rd_values])."Z"; } sub present_local_dt($) { my($dt) = @_; return present_rdns(is_exception($dt) ? $dt : [$dt->local_rd_values]); } sub present_offset($) { my($offset) = @_; return $offset x 3 if is_exception($offset); my $sign = $offset < 0 ? "-" : "+"; $offset = abs($offset); use integer; my $disp = sprintf("%s%02d:%02d:%02d", $sign, $offset/3600, $offset/60%60, $offset%60); $disp =~ s/(?::00)+\z//; return $disp; } sub present_initialism($) { my($initialism) = @_; return is_exception($initialism) ? $initialism x 3 : $initialism; } sub present_isdst($) { my($isdst) = @_; return is_exception($isdst) ? $isdst : $isdst ? "+" : "-"; } { my $areas; sub areas() {
Re: Olson querying
Dave Rolsky wrote: >The use of Date::ISO8601, Date::JD, and Time::Unix seems a bit odd. >Can't you use DateTime to do all this stuff and avoid the additional >prereqs? Using DateTime would gain minimal convenience. On the downside, it's a heavy module load (both in memory and startup time) and a big dep tree. It's nearly even a circular dep: it requires DT:TZ, so stuff under DT:TZ had best not require DateTime. The prospective App::olson isn't actually a dep of (any version of) DT:TZ, but is closely allied with DT:TZ:Olson. Date::ISO8601 and Date::JD are already used by DT:TZ:Tzfile and DT:TZ:SystemV. Date::ISO8601 is light, and certainly pulls its weight. Date::JD is a bit heavy for what it achieves, due to eager generation of hundreds of subs; it should probably be autoloading. I wouldn't mind replacing the minimal use of Date::JD in DT:TZ:{Tzfile,SystemV} and App::olson with a literal constant. Time::Unix is surprisingly large for what it does, but still small overall, and unproblematic as a dep. > We can safely assume that anyone installing >DateTime::TimeZone has DateTime, I think. Has it available, sure, but better not to force its use, because of the heaviness and (in many applications) abstraction inversion of doing so. For what it's worth, I use DT:TZ in handful of places, but I usually use it with cheap fake DateTime objects, as seen in the test suites for DT:TZ:{Tzfile,SystemV}. I've never needed DateTime's arithmetic or other facilities; I only need a DateTime-alike as a container for RD values to query timezone objects. In fact, the one place where I do use DateTime is only using it that way, predates me developing the cheaper substitute, and will be switched when I get round to it. So I'm inclined to keep DT:TZ and allied code free of any real dependency on DateTime. -zefram
Re: Olson querying
On Sun, 4 Mar 2012, Zefram wrote: As part of the plan for replacing DT:TZ, we discussed the need for a way to list the available timezones, to replace the static DT:TZ:Catalog document. Attached is a prototype of a command-line tool that could take this role. I'd appreciate comments about its current operation and about what it ought to additionally support. The use of Date::ISO8601, Date::JD, and Time::Unix seems a bit odd. Can't you use DateTime to do all this stuff and avoid the additional prereqs? We can safely assume that anyone installing DateTime::TimeZone has DateTime, I think. -dave /* http://VegGuide.org http://blog.urth.org Your guide to all that's veg House Absolute(ly Pointless) */
Olson querying
As part of the plan for replacing DT:TZ, we discussed the need for a way to list the available timezones, to replace the static DT:TZ:Catalog document. Attached is a prototype of a command-line tool that could take this role. I'd appreciate comments about its current operation and about what it ought to additionally support. -zefram #!perl { use 5.006; } use warnings; use strict; use Date::ISO8601 0.000 qw(present_ymd); use Date::JD 0.005 qw(rdn_to_cjdnn); use DateTime::TimeZone::Olson (); use Getopt::Std qw(getopts); use Params::Classify qw(is_string); use Time::OlsonTZ::Data (); use Time::Unix qw(time); our $VERSION = "0.000"; my %command; $command{version} = sub () { getopts("", {}) or die "bad options\n"; die "bad arguments\n" if @ARGV; print "modules:\nApp::olson $VERSION\n"; foreach my $mod (qw(DateTime::TimeZone::Olson Time::OlsonTZ::Data)) { no strict "refs"; print "$mod ${qq(${mod}::VERSION)}\n"; } print "Olson database: @{[DateTime::TimeZone::Olson::olson_version]}\n"; }; { package FakeUtcDateTime; sub new { my($class, $rdns) = @_; return bless({ rdn => $rdns->[0], sod => $rdns->[1] }, $class); } sub utc_rd_values { ($_[0]->{rdn}, $_[0]->{sod}, 0) } } { package FakeLocalDateTime; sub new { my($class, $rdns) = @_; return bless({ rdn => $rdns->[0], sod => $rdns->[1] }, $class); } sub local_rd_values { ($_[0]->{rdn}, $_[0]->{sod}, 0) } } sub handle_exception($$) { my($val, $err) = @_; if($err =~ /\A time\ [-:TZ0-9]+\ is\ not\ represented\ in\ the\ [!-~]+ \ timezone\ due\ to\ (zone\ disuse|)\b /x) { return $1 eq "zone disuse" ? "!" : "?"; } elsif($err ne "") { return "*"; } else { return $val; } } sub is_exception($) { return is_string($_[0]) && $_[0] =~ /\A[!?*]\z/; } sub rdns_offset($$) { my($rdns, $offset) = @_; return $rdns if is_exception($rdns); return $offset if is_exception($offset); my($rdn, $sod) = @$rdns; $sod += $offset; use integer; my $doff = $sod < 0 ? -((86399-$sod) / 86400) : $sod / 86400; $rdn += $doff; $sod -= 86400*$doff; return [$rdn, $sod]; } sub present_rdns($) { my($rdns) = @_; return $rdns x 19 if is_exception($rdns); my($rdn, $sod) = @$rdns; use integer; return present_ymd(rdn_to_cjdnn($rdn)). "T".sprintf("%02d:%02d:%02d", $sod/3600, $sod/60%60, $sod%60); } sub now_utc_dt() { my $now_unixtime = time; my $now_utc_rdn = 719163 + int($now_unixtime/86400); my $now_utc_sod = $now_unixtime % 86400; return FakeUtcDateTime->new([$now_utc_rdn, $now_utc_sod]); } sub utc_to_local_dt($$) { my($utcdt, $offset) = @_; return $utcdt if is_exception($utcdt); return $offset if is_exception($offset); return FakeLocalDateTime->new( rdns_offset([$utcdt->utc_rd_values], $offset)); } sub local_to_utc_dt($$) { my($lcldt, $offset) = @_; return $lcldt if is_exception($lcldt); return $offset if is_exception($offset); return FakeUtcDateTime->new( rdns_offset([$lcldt->utc_rd_values], -$offset)); } sub present_utc_dt($) { my($dt) = @_; return present_rdns(is_exception($dt) ? $dt : [$dt->utc_rd_values])."Z"; } sub present_local_dt($) { my($dt) = @_; return present_rdns(is_exception($dt) ? $dt : [$dt->local_rd_values]); } sub present_offset($) { my($offset) = @_; return sprintf("%-9s", $offset x 3) if is_exception($offset); my $sign = $offset < 0 ? "-" : "+"; $offset = abs($offset); use integer; my $disp = sprintf("%s%02d:%02d:%02d", $sign, $offset/3600, $offset/60%60, $offset%60); $disp =~ s/(?::00)+\z//; return sprintf("%-9s", $disp); } sub present_abbreviation($) { my($abbrev) = @_; return sprintf("%-6s", is_exception($abbrev) ? $abbrev x 3 : $abbrev); } sub present_isdst($) { my($isdst) = @_; return is_exception($isdst) ? $isdst : $isdst ? "+" : "-"; } { my $continents; sub continents() { $continents ||= do { my %continents; foreach my $country ( values %{DateTime::TimeZone::Olson::olson_country_selection()} ) { foreach my $region (values %{$country->{regions}}) { $continents{$1} = undef if $region->{timezone_name} =~ m#\A([^/]+)/#; } } \%continents; } } } $command{zones} = sub () { my %opts; getopts("C:N:tado", \%opts) or die "bad options\n"; die "bad arguments\n" if @ARGV;