Re: Olson querying

2012-05-08 Thread Rick Measham
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

2012-05-08 Thread Randal L. Schwartz
> "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

2012-03-06 Thread Zefram
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

2012-03-05 Thread Rick Measham

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

2012-03-05 Thread Zefram
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

2012-03-05 Thread Zefram
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

2012-03-04 Thread Dave Rolsky

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

2012-03-04 Thread Zefram
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;