package Time::Zone;
=head1 NAME
Time::Zone -- miscellaneous timezone manipulations routines
=head1 SYNOPSIS
use Time::Zone;
print tz2zone();
print tz2zone($ENV{'TZ'});
print tz2zone($ENV{'TZ'}, time());
print tz2zone($ENV{'TZ'}, undef, $isdst);
$offset = tz_local_offset();
$offset = tz_offset($TZ);
=head1 DESCRIPTION
This is a collection of miscellaneous timezone manipulation routines.
C<tz2zone()> parses the TZ environment variable and returns a timezone
string suitable for inclusion in L<date>-like output. It opionally takes
a timezone string, a time, and a is-dst flag.
C<tz_local_offset()> determins the offset from GMT time in seconds. It
only does the calculation once.
C<tz_offset()> determines the offset from GMT in seconds of a specified
timezone.
C<tz_name()> determines the name of the timezone based on its offset
=head1 AUTHORS
Graham Barr <gbarr@pobox.com>
David Muir Sharnoff <muir@idiom.com>
Paul Foley <paul@ascent.com>
=cut
require 5.002;
require Exporter;
use Carp;
use strict;
use vars qw(@ISA @EXPORT $VERSION @tz_local);
@ISA = qw(Exporter);
@EXPORT = qw(tz2zone tz_local_offset tz_offset tz_name);
$VERSION = "2.22";
sub tz2zone (;$$$)
{
my($TZ, $time, $isdst) = @_;
use vars qw(%tzn_cache);
$TZ = defined($ENV{'TZ'}) ? ( $ENV{'TZ'} ? $ENV{'TZ'} : 'GMT' ) : ''
unless $TZ;
if (! defined $isdst) {
my $j;
$time = time() unless $time;
($j, $j, $j, $j, $j, $j, $j, $j, $isdst) = localtime($time);
}
if (defined $tzn_cache{$TZ}->[$isdst]) {
return $tzn_cache{$TZ}->[$isdst];
}
if ($TZ =~ /^
( [^:\d+\-,] {3,} )
( [+-] ?
\d {1,2}
( : \d {1,2} ) {0,2}
)
( [^\d+\-,] {3,} )?
/x
) {
my $dsttz = defined($4) ? $4 : $1;
$TZ = $isdst ? $dsttz : $1;
$tzn_cache{$TZ} = [ $1, $dsttz ];
} else {
$tzn_cache{$TZ} = [ $TZ, $TZ ];
}
return $TZ;
}
sub tz_local_offset (;$)
{
my ($time) = @_;
$time = time() unless $time;
my (@l) = localtime($time);
my $isdst = $l[8];
if (defined($tz_local[$isdst])) {
return $tz_local[$isdst];
}
$tz_local[$isdst] = &calc_off($time);
return $tz_local[$isdst];
}
sub calc_off
{
my ($time) = @_;
my (@l) = localtime($time);
my (@g) = gmtime($time);
my $off;
$off = $l[0] - $g[0]
+ ($l[1] - $g[1]) * 60
+ ($l[2] - $g[2]) * 3600;
if ($l[7] == $g[7]) {
} elsif ($l[7] == $g[7] + 1) {
$off += 86400;
} elsif ($l[7] == $g[7] - 1) {
$off -= 86400;
} elsif ($l[7] < $g[7]) {
$off += 86400;
} else {
$off -= 86400;
}
return $off;
}
CONFIG: {
use vars qw(%dstZone %zoneOff %dstZoneOff %Zone);
my @dstZone = (
"brst" => -2*3600, "adt" => -3*3600, "edt" => -4*3600, "cdt" => -5*3600, "mdt" => -6*3600, "pdt" => -7*3600, "ydt" => -8*3600, "hdt" => -9*3600, "bst" => +1*3600, "mest" => +2*3600, "sst" => +2*3600, "fst" => +2*3600, "cest" => +2*3600, "eest" => +3*3600, "wadt" => +8*3600, "kdt" => +10*3600, "eadt" => +11*3600, "nzd" => +13*3600, "nzdt" => +13*3600, );
my @Zone = (
"gmt" => 0, "ut" => 0, "utc" => 0,
"wet" => 0, "wat" => -1*3600, "at" => -2*3600, "fnt" => -2*3600, "brt" => -3*3600, "mnt" => -4*3600, "ewt" => -4*3600, "ast" => -4*3600, "est" => -5*3600, "act" => -5*3600, "cst" => -6*3600, "mst" => -7*3600, "pst" => -8*3600, "yst" => -9*3600, "hst" => -10*3600, "cat" => -10*3600, "ahst" => -10*3600, "nt" => -11*3600, "idlw" => -12*3600, "cet" => +1*3600, "mez" => +1*3600, "ect" => +1*3600, "met" => +1*3600, "mewt" => +1*3600, "swt" => +1*3600, "set" => +1*3600, "fwt" => +1*3600, "eet" => +2*3600, "ukr" => +2*3600, "bt" => +3*3600, "zp4" => +4*3600, "zp5" => +5*3600, "zp6" => +6*3600, "wst" => +8*3600, "hkt" => +8*3600, "cct" => +8*3600, "jst" => +9*3600, "kst" => +9*3600, "east" => +10*3600, "gst" => +10*3600, "nzt" => +12*3600, "nzst" => +12*3600, "idle" => +12*3600, );
%Zone = @Zone;
%dstZone = @dstZone;
%zoneOff = reverse(@Zone);
%dstZoneOff = reverse(@dstZone);
}
sub tz_offset (;$$)
{
my ($zone, $time) = @_;
return &tz_local_offset($time) unless($zone);
$time = time() unless $time;
my(@l) = localtime($time);
my $dst = $l[8];
$zone = lc $zone;
if($zone =~ /^(([\-\+])\d\d?)(\d\d)$/) {
my $v = $2 . $3;
return $1 * 3600 + $v * 60;
} elsif (exists $dstZone{$zone} && ($dst || !exists $Zone{$zone})) {
return $dstZone{$zone};
} elsif(exists $Zone{$zone}) {
return $Zone{$zone};
}
undef;
}
sub tz_name (;$$)
{
my ($off, $dst) = @_;
$off = tz_offset()
unless(defined $off);
$dst = (localtime(time))[8]
unless(defined $dst);
if (exists $dstZoneOff{$off} && ($dst || !exists $zoneOff{$off})) {
return $dstZoneOff{$off};
} elsif (exists $zoneOff{$off}) {
return $zoneOff{$off};
}
sprintf("%+05d", int($off / 60) * 100 + $off % 60);
}
1;