1# $Id: TZ.pm 2902 2007-08-08 19:04:08Z verthezp $ 2# $URL: file:///var/lib/svn/intclock/tags/R2_13/lib/Intclock/TZ.pm $ 3#___________________________________________________________________ 4# 5# Timezone handling routines for intclock 6#___________________________________________________________________ 7 8# Copyright (C) 2004-2007 by Peter Verthez 9 10# This program is free software; you can redistribute it and/or modify 11# it under the terms of the GNU General Public License as published by 12# the Free Software Foundation; either version 2, or (at your option) 13# any later version. 14 15# This program is distributed in the hope that it will be useful, 16# but WITHOUT ANY WARRANTY; without even the implied warranty of 17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18# GNU General Public License for more details. 19 20# You should have received a copy of the GNU General Public License 21# along with this program; if not, write to the Free Software 22# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 23# 02111-1307, USA. 24 25# Written by Peter Verthez, <Peter.Verthez@advalvas.be>. 26# Based on Jens-Ulrik Petersen's hsclock 27 28package Intclock::TZ; 29 30use strict; 31use diagnostics; 32use POSIX; 33use vars qw($zonedir @zonedirs $countryfile $zonefile 34 %countryhash %zonehash 35 $cldrterrfile %cldrterrhash 36 $cldrzonefile %cldrzonehash 37 %invzonehash); 38 39BEGIN { 40 @zonedirs = ( "/usr/share/zoneinfo", 41 "/usr/lib/zoneinfo", 42 "/usr/local/share/zoneinfo", 43 "/usr/local/lib/zoneinfo", 44 "/etc/zoneinfo", 45 ); 46 47 $countryfile = "iso3166.tab"; 48 $zonefile = "zone.tab"; 49 $cldrterrfile = "territories.dat"; 50 $cldrzonefile = "zones.dat"; 51} 52 53sub init { 54 my ($language) = @_; 55 set_timezone(); 56 _get_zone_dir(); 57 _get_countries(); 58 if (defined $language) { 59 _get_cldr(); 60 } 61 _get_zones($language); 62} 63 64sub _get_zone_dir { 65 # some heuristics: 66 # - if TZDIR is set and the directory exists, use it 67 if (exists $ENV{"TZDIR"} and -d $ENV{"TZDIR"}) { 68 $zonedir = $ENV{"TZDIR"}; 69 } 70 # - if 'tzselect' exists, try to find the default TZDIR there 71 if (!$zonedir or ! -d $zonedir) { 72 my $tzselect=`which tzselect`; 73 chomp $tzselect; 74 if (-r $tzselect) { 75 my $line = `grep "TZDIR=" $tzselect`; 76 if ($line =~ /^: \$\{TZDIR=(.*?)\}/) { 77 $zonedir = $1; 78 } 79 } 80 } 81 # - otherwise, use the fixed list of directories above to search 82 if (!$zonedir or ! -d $zonedir) { 83 foreach my $dir (@zonedirs) { 84 if (-d $dir) { 85 $zonedir = $dir; 86 last; 87 } 88 } 89 } 90 ($zonedir and -d $zonedir) or die "No zoneinfo directory found\n"; 91} 92 93sub _get_countries { 94 open INPUT, "/usr/share/misc/iso3166" or die "Can't read country file\n"; 95 while (<INPUT>) { 96 next if /^\#/; 97 next if /^\s*$/; 98 my ($code, $name) = split /\t/; 99 chomp $name; 100 $countryhash{$code} = $name; 101 } 102 close INPUT; 103} 104 105sub _get_cldr_sub { 106 my ($file, $hashref, $currlang) = @_; 107 open INPUT, "<:utf8", $file or die "Can't read CLDR data file '$file'\n"; 108 my $lang; 109 while (<INPUT>) { 110 my $line = $_; 111 next if /^\#/; 112 next if /^\s*$/; 113 if ($line =~ /^\[LANG=(.*?)\]/) { 114 $lang = $1; 115 } 116 elsif ($lang and (index($currlang, $lang) == 0) 117 and $line =~ /^\s*(.+?)=(.*)$/) { 118 my ($code, $name) = ($1, $2); 119 $name =~ s/\s*$//; 120 $name =~ s/\&\#x([A-Z0-9]+);/chr(hex($1))/eg; 121 if ($name !~ /^\s*$/) { 122 $hashref->{$code} = $name; 123 } 124 } 125 } 126 close INPUT; 127} 128 129sub _get_cldr { 130 my $curr_lang = $ENV{"LANG"}; 131 if ($curr_lang) { 132 my $datadir = Intclock::Config::get_datadir(); 133 _get_cldr_sub("$datadir/$cldrterrfile", \%cldrterrhash, $curr_lang); 134 _get_cldr_sub("$datadir/$cldrzonefile", \%cldrzonehash, $curr_lang); 135 } 136} 137 138sub _get_zones { 139 my ($language) = @_; 140 open INPUT, "$zonedir/$zonefile" or die "Can't read zone file\n"; 141 while (<INPUT>) { 142 next if /^\#/; 143 next if /^\s*$/; 144 my ($country, $coord, $tz, $comments) = split /\t/; 145 chomp $tz; 146 my $full_tz = $tz; 147 $comments ||= ""; 148 chomp $comments; 149 $tz =~ s|^([^/]+)/||; 150 my $continent = $1; 151 152 $coord =~ s/^(.*?)([\-\+]\d+)$/$2/; 153 my $longitude = substr($coord, 0, 6); 154 155 my %data = ("comments" => $comments, 156 "long" => $longitude, 157 "continent" => $continent); 158 159 my $full_continent = $continent; 160 if ($continent =~ /^Arctic|Atlantic|Indian|Pacific$/) { 161 $full_continent = "$continent Ocean"; 162 } 163 164 my $l_cont; 165 if (defined $language) { 166 eval { 167 $l_cont = $language->maketext($full_continent); 168 }; 169 if ($@) { 170 print "WARNING: '$full_continent' not translated\n"; 171 $l_cont = $full_continent; 172 } 173 } 174 else { 175 $l_cont = $full_continent; 176 } 177 178 my $l_country = $countryhash{$country}; 179 if (defined $language and exists $cldrterrhash{$country}) { 180 $l_country = $cldrterrhash{$country}; 181 } 182 183 my $l_tz = $tz; 184 if (defined $language and exists $cldrzonehash{$full_tz}) { 185 $l_tz = $cldrzonehash{$full_tz}; 186 $data{"translated_zone"} = $l_tz; 187 } 188 else { 189 $l_tz =~ s|^.*?/||; 190 $l_tz =~ s/_/ /g; 191 } 192 $zonehash{$l_cont}->{$l_country}->{$tz} = \%data; 193 $invzonehash{$full_tz} = [ $l_country, $l_tz, 194 $zonehash{$l_cont}->{$l_country}]; 195 } 196 close INPUT; 197 undef %countryhash; 198 undef %cldrterrhash; 199} 200 201sub zone_info { 202 return (\%zonehash, \%invzonehash); 203} 204 205sub exists { 206 my ($tz) = @_; 207 return (-f "$zonedir/$tz"); 208} 209 210sub set_timezone { 211 my ($tz) = @_; 212 $ENV{"TZ"} = $tz if defined $tz; 213 POSIX::tzset(); 214} 215 216sub get_timezone_names { 217 my ($tz) = @_; 218 set_timezone($tz) if defined $tz; 219 return POSIX::tzname(); 220} 221 222sub in_timezone { 223 my ($time, $timezone) = @_; 224 set_timezone($timezone); 225 my @localtime = localtime($time); 226 return \@localtime; 227} 228 2291; 230