File Coverage

blib/lib/Time/Timezone.pm
Criterion Covered Total %
statement 48 63 76.1
branch 24 44 54.5
condition 4 12 33.3
subroutine 9 10 90.0
pod 0 5 0.0
total 85 134 63.4


line stmt bran cond sub pod time code
1             package Time::Timezone;
2              
3             require 5.002;
4              
5             require Exporter;
6             @ISA = qw(Exporter);
7             @EXPORT = qw(tz2zone tz_local_offset tz_offset tz_name);
8             @EXPORT_OK = qw();
9              
10 4     4   54 use Carp;
  4         8  
  4         283  
11 4     4   23 use strict;
  4         9  
  4         142  
12              
13             # Parts stolen from code by Paul Foley
14              
15 4     4   27 use vars qw($VERSION);
  4         11  
  4         363  
16              
17             $VERSION = 2015.0925;
18              
19             sub tz2zone
20             {
21 4     4 0 10 my($TZ, $time, $isdst) = @_;
22              
23 4     4   22 use vars qw(%tzn_cache);
  4         7  
  4         3696  
24              
25 4 50       44 $TZ = defined($ENV{'TZ'}) ? ( $ENV{'TZ'} ? $ENV{'TZ'} : 'GMT' ) : ''
    50          
    50          
26             unless $TZ;
27              
28             # Hack to deal with 'PST8PDT' format of TZ
29             # Note that this can't deal with all the esoteric forms, but it
30             # does recognize the most common: [:]STDoff[DST[off][,rule]]
31              
32 4 100       18 if (! defined $isdst) {
33 1         1 my $j;
34 1 50       4 $time = time() unless defined $time;
35 1         6 ($j, $j, $j, $j, $j, $j, $j, $j, $isdst) = localtime($time);
36             }
37              
38 4 50       22 if (defined $tzn_cache{$TZ}->[$isdst]) {
39 0         0 return $tzn_cache{$TZ}->[$isdst];
40             }
41            
42 4 50       34 if ($TZ =~ /^
43             ( [^:\d+\-,] {3,} )
44             ( [+-] ?
45             \d {1,2}
46             ( : \d {1,2} ) {0,2}
47             )
48             ( [^\d+\-,] {3,} )?
49             /x
50             ) {
51 4 100       18 $TZ = $isdst ? $4 : $1;
52 4         23 $tzn_cache{$TZ} = [ $1, $4 ];
53             } else {
54 0         0 $tzn_cache{$TZ} = [ $TZ, $TZ ];
55             }
56 4         26 return $TZ;
57             }
58              
59             sub tz_local_offset
60             {
61 246     246 0 325 my ($time) = @_;
62              
63 246 50       531 $time = time() unless defined $time;
64              
65 246         429 return &calc_off($time);
66             }
67              
68             sub calc_off
69             {
70 246     246 0 321 my ($time) = @_;
71              
72 246         9336 my (@l) = localtime($time);
73 246         1036 my (@g) = gmtime($time);
74              
75 246         406 my $off;
76              
77 246         518 $off = $l[0] - $g[0]
78             + ($l[1] - $g[1]) * 60
79             + ($l[2] - $g[2]) * 3600;
80              
81             # subscript 7 is yday.
82              
83 246 100       728 if ($l[7] == $g[7]) {
    100          
    100          
    50          
84             # done
85             } elsif ($l[7] == $g[7] + 1) {
86 4         9 $off += 86400;
87             } elsif ($l[7] == $g[7] - 1) {
88 102         144 $off -= 86400;
89             } elsif ($l[7] < $g[7]) {
90             # crossed over a year boundary!
91             # localtime is beginning of year, gmt is end
92             # therefore local is ahead
93 0         0 $off += 86400;
94             } else {
95 5         8 $off -= 86400;
96             }
97              
98 246         829 return $off;
99             }
100              
101             # constants
102             # The rest of the file originally comes from Graham Barr
103             #
104             # Some references:
105             # http://www.weltzeituhr.com/laender/zeitzonen_e.shtml
106             # http://www.worldtimezone.com/wtz-names/timezonenames.html
107             # http://www.timegenie.com/timezones.php
108              
109             CONFIG: {
110 4     4   25 use vars qw(%dstZone %zoneOff %dstZoneOff %Zone);
  4         8  
  4         3940  
111              
112             %dstZone = (
113             "brst" => -2*3600, # Brazil Summer Time (East Daylight)
114             "adt" => -3*3600, # Atlantic Daylight
115             "edt" => -4*3600, # Eastern Daylight
116             "cdt" => -5*3600, # Central Daylight
117             "mdt" => -6*3600, # Mountain Daylight
118             "pdt" => -7*3600, # Pacific Daylight
119             "ydt" => -8*3600, # Yukon Daylight
120             "hdt" => -9*3600, # Hawaii Daylight
121             "bst" => +1*3600, # British Summer
122             "mest" => +2*3600, # Middle European Summer
123             "met dst" => +2*3600, # Middle European Summer
124             "sst" => +2*3600, # Swedish Summer
125             "fst" => +2*3600, # French Summer
126             "eest" => +3*3600, # Eastern European Summer
127             "cest" => +2*3600, # Central European Daylight
128             "wadt" => +8*3600, # West Australian Daylight
129             "kdt" => +10*3600, # Korean Daylight
130             # "cadt" => +10*3600+1800, # Central Australian Daylight
131             "eadt" => +11*3600, # Eastern Australian Daylight
132             "nzdt" => +13*3600, # New Zealand Daylight
133             );
134              
135             # not included due to ambiguity:
136             # IST Indian Standard Time +5.5
137             # Ireland Standard Time 0
138             # Israel Standard Time +2
139             # IDT Ireland Daylight Time +1
140             # Israel Daylight Time +3
141             # AMST Amazon Standard Time / -3
142             # Armenia Standard Time +8
143             # BST Brazil Standard -3
144              
145             %Zone = (
146             "gmt" => 0, # Greenwich Mean
147             "ut" => 0, # Universal (Coordinated)
148             "utc" => 0,
149             "wet" => 0, # Western European
150             "wat" => -1*3600, # West Africa
151             "azost" => -1*3600, # Azores Standard Time
152             "cvt" => -1*3600, # Cape Verde Time
153             "at" => -2*3600, # Azores
154             "fnt" => -2*3600, # Brazil Time (Extreme East - Fernando Noronha)
155             "ndt" => -2*3600-1800,# Newfoundland Daylight
156             "art" => -3*3600, # Argentina Time
157             # For completeness. BST is also British Summer, and GST is also Guam Standard.
158             # "gst" => -3*3600, # Greenland Standard
159             "nft" => -3*3600-1800,# Newfoundland
160             # "nst" => -3*3600-1800,# Newfoundland Standard
161             "mnt" => -4*3600, # Brazil Time (West Standard - Manaus)
162             "ewt" => -4*3600, # U.S. Eastern War Time
163             "ast" => -4*3600, # Atlantic Standard
164             "bot" => -4*3600, # Bolivia Time
165             "vet" => -4*3600, # Venezuela Time
166             "est" => -5*3600, # Eastern Standard
167             "cot" => -5*3600, # Colombia Time
168             "act" => -5*3600, # Brazil Time (Extreme West - Acre)
169             "pet" => -5*3600, # Peru Time
170             "cst" => -6*3600, # Central Standard
171             "cest" => +2*3600, # Central European Summer
172             "mst" => -7*3600, # Mountain Standard
173             "pst" => -8*3600, # Pacific Standard
174             "yst" => -9*3600, # Yukon Standard
175             "hst" => -10*3600, # Hawaii Standard
176             "cat" => -10*3600, # Central Alaska
177             "ahst" => -10*3600, # Alaska-Hawaii Standard
178             "taht" => -10*3600, # Tahiti Time
179             "nt" => -11*3600, # Nome
180             "idlw" => -12*3600, # International Date Line West
181             "cet" => +1*3600, # Central European
182             "mez" => +1*3600, # Central European (German)
183             "met" => +1*3600, # Middle European
184             "mewt" => +1*3600, # Middle European Winter
185             "swt" => +1*3600, # Swedish Winter
186             "set" => +1*3600, # Seychelles
187             "fwt" => +1*3600, # French Winter
188             "west" => +1*3600, # Western Europe Summer Time
189             "eet" => +2*3600, # Eastern Europe, USSR Zone 1
190             "ukr" => +2*3600, # Ukraine
191             "sast" => +2*3600, # South Africa Standard Time
192             "bt" => +3*3600, # Baghdad, USSR Zone 2
193             "eat" => +3*3600, # East Africa Time
194             # "it" => +3*3600+1800,# Iran
195             "irst" => +3*3600+1800,# Iran Standard Time
196             "zp4" => +4*3600, # USSR Zone 3
197             "msd" => +4*3600, # Moscow Daylight Time
198             "sct" => +4*3600, # Seychelles Time
199             "zp5" => +5*3600, # USSR Zone 4
200             "azst" => +5*3600, # Azerbaijan Summer Time
201             "mvt" => +5*3600, # Maldives Time
202             "uzt" => +5*3600, # Uzbekistan Time
203             "ist" => +5*3600+1800,# Indian Standard
204             "zp6" => +6*3600, # USSR Zone 5
205             "lkt" => +6*3600, # Sri Lanka Time
206             "pkst" => +6*3600, # Pakistan Summer Time
207             "yekst" => +6*3600, # Yekaterinburg Summer Time
208             # For completeness. NST is also Newfoundland Stanard, and SST is also Swedish Summer.
209             # "nst" => +6*3600+1800,# North Sumatra
210             # "sst" => +7*3600, # South Sumatra, USSR Zone 6
211             "wast" => +7*3600, # West Australian Standard
212             "ict" => +7*3600, # Indochina Time
213             "wit" => +7*3600, # Western Indonesia Time
214             # "jt" => +7*3600+1800,# Java (3pm in Cronusland!)
215             "cct" => +8*3600, # China Coast, USSR Zone 7
216             "wst" => +8*3600, # West Australian Standard
217             "hkt" => +8*3600, # Hong Kong
218             "bnt" => +8*3600, # Brunei Darussalam Time
219             "cit" => +8*3600, # Central Indonesia Time
220             "myt" => +8*3600, # Malaysia Time
221             "pht" => +8*3600, # Philippines Time
222             "sgt" => +8*3600, # Singapore Time
223             "jst" => +9*3600, # Japan Standard, USSR Zone 8
224             "kst" => +9*3600, # Korean Standard
225             # "cast" => +9*3600+1800,# Central Australian Standard
226             "east" => +10*3600, # Eastern Australian Standard
227             "gst" => +10*3600, # Guam Standard, USSR Zone 9
228             "nct" => +11*3600, # New Caledonia Time
229             "nzt" => +12*3600, # New Zealand
230             "nzst" => +12*3600, # New Zealand Standard
231             "fjt" => +12*3600, # Fiji Time
232             "idle" => +12*3600, # International Date Line East
233             );
234              
235             %zoneOff = reverse(%Zone);
236             %dstZoneOff = reverse(%dstZone);
237              
238             # Preferences
239              
240             $zoneOff{0} = 'gmt';
241             $dstZoneOff{3600} = 'bst';
242              
243             }
244              
245             sub tz_offset
246             {
247 166     166 0 334 my ($zone, $time) = @_;
248              
249 166 50       355 return &tz_local_offset() unless($zone);
250              
251 166 50       324 $time = time() unless defined $time;
252 166         732 my(@l) = localtime($time);
253 166         304 my $dst = $l[8];
254              
255 166         262 $zone = lc $zone;
256              
257 166 50 66     951 if ($zone =~ /^([\-\+]\d{3,4})$/) {
    100 66        
    50          
258 0 0       0 my $sign = $1 < 0 ? -1 : 1 ;
259 0         0 my $v = abs(0 + $1);
260 0         0 return $sign * 60 * (int($v / 100) * 60 + ($v % 100));
261             } elsif (exists $dstZone{$zone} && ($dst || !exists $Zone{$zone})) {
262 126         632 return $dstZone{$zone};
263             } elsif(exists $Zone{$zone}) {
264 40         175 return $Zone{$zone};
265             }
266 0           undef;
267             }
268              
269             sub tz_name
270             {
271 0     0 0   my ($off, $time) = @_;
272              
273 0 0         $time = time() unless defined $time;
274 0           my(@l) = localtime($time);
275 0           my $dst = $l[8];
276              
277 0 0 0       if (exists $dstZoneOff{$off} && ($dst || !exists $zoneOff{$off})) {
    0 0        
278 0           return $dstZoneOff{$off};
279             } elsif (exists $zoneOff{$off}) {
280 0           return $zoneOff{$off};
281             }
282 0           sprintf("%+05d", int($off / 60) * 100 + $off % 60);
283             }
284              
285             1;
286              
287             __END__