line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package DateTimeX::Lite::TimeZone; |
2
|
56
|
|
|
56
|
|
311332
|
use strict; |
|
56
|
|
|
|
|
119
|
|
|
56
|
|
|
|
|
2006
|
|
3
|
56
|
|
|
56
|
|
307
|
use warnings; |
|
56
|
|
|
|
|
99
|
|
|
56
|
|
|
|
|
1814
|
|
4
|
|
|
|
|
|
|
|
5
|
56
|
|
|
56
|
|
371
|
use Carp (); |
|
56
|
|
|
|
|
102
|
|
|
56
|
|
|
|
|
1049
|
|
6
|
56
|
|
|
56
|
|
73846
|
use DateTimeX::Lite::TimeZone::Catalog; |
|
56
|
|
|
|
|
191
|
|
|
56
|
|
|
|
|
3163
|
|
7
|
56
|
|
|
56
|
|
51753
|
use DateTimeX::Lite::TimeZone::Floating; |
|
56
|
|
|
|
|
152
|
|
|
56
|
|
|
|
|
2032
|
|
8
|
56
|
|
|
56
|
|
41979
|
use DateTimeX::Lite::TimeZone::Local; |
|
56
|
|
|
|
|
174
|
|
|
56
|
|
|
|
|
2271
|
|
9
|
56
|
|
|
56
|
|
459
|
use DateTimeX::Lite::TimeZone::OffsetOnly; |
|
56
|
|
|
|
|
257
|
|
|
56
|
|
|
|
|
2233
|
|
10
|
56
|
|
|
56
|
|
315
|
use DateTimeX::Lite::TimeZone::UTC; |
|
56
|
|
|
|
|
103
|
|
|
56
|
|
|
|
|
10538
|
|
11
|
56
|
|
|
56
|
|
43962
|
use DateTimeX::Lite::OlsonDB; |
|
56
|
|
|
|
|
181
|
|
|
56
|
|
|
|
|
3921
|
|
12
|
56
|
|
|
56
|
|
55322
|
use File::ShareDir qw(dist_file); |
|
56
|
|
|
|
|
472259
|
|
|
56
|
|
|
|
|
7395
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our %CachedTimeZones; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# the offsets for each span element |
17
|
56
|
|
|
56
|
|
573
|
use constant UTC_START => 0; |
|
56
|
|
|
|
|
150
|
|
|
56
|
|
|
|
|
4100
|
|
18
|
56
|
|
|
56
|
|
581
|
use constant UTC_END => 1; |
|
56
|
|
|
|
|
137
|
|
|
56
|
|
|
|
|
3109
|
|
19
|
56
|
|
|
56
|
|
311
|
use constant LOCAL_START => 2; |
|
56
|
|
|
|
|
200
|
|
|
56
|
|
|
|
|
3053
|
|
20
|
56
|
|
|
56
|
|
304
|
use constant LOCAL_END => 3; |
|
56
|
|
|
|
|
108
|
|
|
56
|
|
|
|
|
3734
|
|
21
|
56
|
|
|
56
|
|
307
|
use constant OFFSET => 4; |
|
56
|
|
|
|
|
108
|
|
|
56
|
|
|
|
|
3253
|
|
22
|
56
|
|
|
56
|
|
295
|
use constant IS_DST => 5; |
|
56
|
|
|
|
|
134
|
|
|
56
|
|
|
|
|
2848
|
|
23
|
56
|
|
|
56
|
|
351
|
use constant SHORT_NAME => 6; |
|
56
|
|
|
|
|
110
|
|
|
56
|
|
|
|
|
280000
|
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
my %SpecialName = map { $_ => 1 } qw( EST MST HST CET EET MET WET EST5EDT CST6CDT MST7MDT PST8PDT ); |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub load { |
28
|
12001
|
|
|
12001
|
0
|
226098
|
my ($class, %p) = @_; |
29
|
|
|
|
|
|
|
|
30
|
12001
|
|
|
|
|
20617
|
my $name = $p{name}; |
31
|
12001
|
|
|
|
|
28778
|
my $conf; |
32
|
|
|
|
|
|
|
my $zone; |
33
|
12001
|
100
|
|
|
|
31558
|
if (defined $name) { |
34
|
12000
|
|
|
|
|
21414
|
my $links = \%DateTimeX::Lite::TimeZone::Catalog::LINKS; |
35
|
12000
|
100
|
|
|
|
67046
|
if ( exists $links->{ $name } ) { |
|
|
50
|
|
|
|
|
|
36
|
276
|
|
|
|
|
694
|
$name = $links->{ $name }; |
37
|
|
|
|
|
|
|
} elsif ( exists $links->{ uc $name } ) { |
38
|
0
|
|
|
|
|
0
|
$name = $links->{ uc $name }; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
12001
|
100
|
|
|
|
27145
|
if (defined $name) { |
43
|
12000
|
100
|
|
|
|
73278
|
return $CachedTimeZones{$name} if $CachedTimeZones{$name}; |
44
|
1033
|
100
|
100
|
|
|
22393
|
unless ( $name =~ m,/, || $SpecialName{ $name }) { |
45
|
90
|
100
|
|
|
|
353
|
if ( $name eq 'floating' ) { |
46
|
26
|
|
|
|
|
387
|
return $CachedTimeZones{$name} = DateTimeX::Lite::TimeZone::Floating->new; |
47
|
|
|
|
|
|
|
} |
48
|
64
|
100
|
|
|
|
509
|
if ( $name eq 'local' ) { |
49
|
1
|
|
|
|
|
9
|
return $CachedTimeZones{$name} = DateTimeX::Lite::TimeZone::Local->TimeZone(); |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
63
|
100
|
100
|
|
|
385
|
if ( $name eq 'UTC' || $name eq 'Z' ) { |
53
|
39
|
|
|
|
|
470
|
return $CachedTimeZones{$name} = DateTimeX::Lite::TimeZone::UTC->new; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
24
|
|
|
|
|
233
|
return $CachedTimeZones{$name} = DateTimeX::Lite::TimeZone::OffsetOnly->new( offset => $name ); |
57
|
|
|
|
|
|
|
} |
58
|
943
|
|
|
|
|
2734
|
$conf = _load_time_zone($name); |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
944
|
100
|
|
|
|
10103
|
if (! $conf) { |
62
|
5
|
50
|
|
|
|
29
|
my $x = $ENV{DATETIMEX_LITE_DEBUG} ? \&Carp::confess : \&Carp::croak ; |
63
|
5
|
|
100
|
|
|
992
|
$x->( "The timezone '" . ($p{name} || 'undef') . "' could not be loaded, or is an invalid name.\n" ); |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
939
|
|
|
|
|
13827
|
$zone = $class->new(%$conf); |
67
|
|
|
|
|
|
|
|
68
|
939
|
50
|
|
|
|
4515
|
if ( $zone->is_olson() ) { |
69
|
0
|
0
|
|
|
|
0
|
my $object_version = |
70
|
|
|
|
|
|
|
$zone->can('olson_version') |
71
|
|
|
|
|
|
|
? $zone->olson_version() |
72
|
|
|
|
|
|
|
: 'unknown'; |
73
|
0
|
|
|
|
|
0
|
my $catalog_version = DateTimeX::Lite::TimeZone::Catalog->OlsonVersion(); |
74
|
|
|
|
|
|
|
|
75
|
0
|
0
|
|
|
|
0
|
if ( $object_version ne $catalog_version ) |
76
|
|
|
|
|
|
|
{ |
77
|
0
|
|
|
|
|
0
|
warn "Loaded $name, which is from an older version ($object_version) of the Olson database than this installation of DateTimeX::Lite::TimeZone ($catalog_version).\n"; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
939
|
|
|
|
|
4275
|
$CachedTimeZones{$name} = $zone; |
82
|
939
|
|
|
|
|
7862
|
return $zone; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
939
|
|
|
939
|
1
|
3324
|
sub new { my $class = shift; bless { @_ }, $class } |
|
939
|
|
|
|
|
7307
|
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub _load_time_zone { |
88
|
943
|
|
|
943
|
|
2684
|
my $name = shift; |
89
|
943
|
|
|
|
|
2848
|
my $file = "$name.dat"; |
90
|
943
|
|
|
|
|
2894
|
$file =~ s/-/_/g; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# Quietly fail here, so we can let the proceeding section croak for us |
93
|
943
|
|
|
|
|
1629
|
eval { |
94
|
943
|
|
|
|
|
6905
|
$file = dist_file( 'DateTimeX-Lite', "DateTimeX/Lite/TimeZone/$file"); |
95
|
|
|
|
|
|
|
}; |
96
|
943
|
50
|
|
|
|
4145738
|
return $file ? do $file : (); |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
16
|
|
|
16
|
0
|
73
|
sub rules { $_[0]->{rules} } |
100
|
17
|
|
|
17
|
0
|
91
|
sub max_year { $_[0]->{max_year} } |
101
|
1118
|
|
|
1118
|
0
|
5524
|
sub last_offset { $_[0]->{last_offset} } |
102
|
1081
|
|
|
1081
|
0
|
3094
|
sub last_observance { $_[0]->{last_observance} } |
103
|
|
|
|
|
|
|
|
104
|
940
|
|
|
940
|
1
|
12257
|
sub is_olson { $_[0]->{is_olson} } |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub is_dst_for_datetime |
107
|
|
|
|
|
|
|
{ |
108
|
56
|
|
|
56
|
0
|
80
|
my $self = shift; |
109
|
|
|
|
|
|
|
|
110
|
56
|
|
|
|
|
135
|
my $span = $self->_span_for_datetime( 'utc', $_[0] ); |
111
|
|
|
|
|
|
|
|
112
|
56
|
|
|
|
|
400
|
return $span->[IS_DST]; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub offset_for_datetime |
116
|
|
|
|
|
|
|
{ |
117
|
417
|
|
|
417
|
1
|
571
|
my $self = shift; |
118
|
|
|
|
|
|
|
|
119
|
417
|
|
|
|
|
1045
|
my $span = $self->_span_for_datetime( 'utc', $_[0] ); |
120
|
|
|
|
|
|
|
|
121
|
416
|
|
|
|
|
1314
|
return $span->[OFFSET]; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub offset_for_local_datetime |
125
|
|
|
|
|
|
|
{ |
126
|
269
|
|
|
269
|
1
|
398
|
my $self = shift; |
127
|
|
|
|
|
|
|
|
128
|
269
|
|
|
|
|
654
|
my $span = $self->_span_for_datetime( 'local', $_[0] ); |
129
|
|
|
|
|
|
|
|
130
|
261
|
|
|
|
|
844
|
return $span->[OFFSET]; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub short_name_for_datetime |
134
|
|
|
|
|
|
|
{ |
135
|
56
|
|
|
56
|
1
|
140
|
my $self = shift; |
136
|
|
|
|
|
|
|
|
137
|
56
|
|
|
|
|
179
|
my $span = $self->_span_for_datetime( 'utc', $_[0] ); |
138
|
|
|
|
|
|
|
|
139
|
56
|
|
|
|
|
479
|
return $span->[SHORT_NAME]; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub _span_for_datetime |
143
|
|
|
|
|
|
|
{ |
144
|
798
|
|
|
798
|
|
1033
|
my $self = shift; |
145
|
798
|
|
|
|
|
1272
|
my $type = shift; |
146
|
798
|
|
|
|
|
948
|
my $dt = shift; |
147
|
|
|
|
|
|
|
|
148
|
798
|
|
|
|
|
1622
|
my $method = $type . '_rd_as_seconds'; |
149
|
|
|
|
|
|
|
|
150
|
798
|
100
|
|
|
|
1874
|
my $end = $type eq 'utc' ? UTC_END : LOCAL_END; |
151
|
|
|
|
|
|
|
|
152
|
798
|
|
|
|
|
877
|
my $span; |
153
|
798
|
|
|
|
|
2589
|
my $seconds = $dt->$method(); |
154
|
798
|
100
|
|
|
|
1922
|
if ( $seconds < $self->max_span->[$end] ) |
155
|
|
|
|
|
|
|
{ |
156
|
783
|
|
|
|
|
1869
|
$span = $self->_spans_binary_search( $type, $seconds ); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
else |
159
|
|
|
|
|
|
|
{ |
160
|
15
|
|
|
|
|
70
|
my $until_year = $dt->utc_year + 1; |
161
|
15
|
|
|
|
|
71
|
$span = $self->_generate_spans_until_match( $until_year, $seconds, $type ); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# This means someone gave a local time that doesn't exist |
165
|
|
|
|
|
|
|
# (like during a transition into savings time) |
166
|
798
|
100
|
|
|
|
2175
|
unless ( defined $span ) |
167
|
|
|
|
|
|
|
{ |
168
|
9
|
|
|
|
|
20
|
my $err = 'Invalid local time for date'; |
169
|
9
|
100
|
|
|
|
39
|
$err .= ' ' . $dt->iso8601 if $type eq 'utc'; |
170
|
9
|
|
|
|
|
42
|
$err .= " in time zone: " . $self->name; |
171
|
9
|
|
|
|
|
19
|
$err .= "\n"; |
172
|
|
|
|
|
|
|
|
173
|
9
|
|
|
|
|
129
|
die $err; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
789
|
|
|
|
|
1672
|
return $span; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub _spans_binary_search |
180
|
|
|
|
|
|
|
{ |
181
|
783
|
|
|
783
|
|
1075
|
my $self = shift; |
182
|
783
|
|
|
|
|
1147
|
my ( $type, $seconds ) = @_; |
183
|
|
|
|
|
|
|
|
184
|
783
|
|
|
|
|
1425
|
my ( $start, $end ) = _keys_for_type($type); |
185
|
|
|
|
|
|
|
|
186
|
783
|
|
|
|
|
1010
|
my $min = 0; |
187
|
783
|
|
|
|
|
906
|
my $max = scalar @{ $self->{spans} } + 1; |
|
783
|
|
|
|
|
1617
|
|
188
|
783
|
|
|
|
|
1552
|
my $i = int( $max / 2 ); |
189
|
|
|
|
|
|
|
# special case for when there are only 2 spans |
190
|
783
|
100
|
100
|
|
|
3602
|
$i++ if $max % 2 && $max != 3; |
191
|
|
|
|
|
|
|
|
192
|
783
|
50
|
|
|
|
842
|
$i = 0 if @{ $self->{spans} } == 1; |
|
783
|
|
|
|
|
2351
|
|
193
|
|
|
|
|
|
|
|
194
|
783
|
|
|
|
|
1069
|
while (1) |
195
|
|
|
|
|
|
|
{ |
196
|
5256
|
|
|
|
|
8054
|
my $current = $self->{spans}[$i]; |
197
|
5256
|
100
|
|
|
|
16182
|
if ( $seconds < $current->[$start] ) |
|
|
100
|
|
|
|
|
|
198
|
|
|
|
|
|
|
{ |
199
|
1988
|
|
|
|
|
2129
|
$max = $i; |
200
|
1988
|
|
|
|
|
2890
|
my $c = int( ( $i - $min ) / 2 ); |
201
|
1988
|
|
100
|
|
|
3402
|
$c ||= 1; |
202
|
|
|
|
|
|
|
|
203
|
1988
|
|
|
|
|
2169
|
$i -= $c; |
204
|
|
|
|
|
|
|
|
205
|
1988
|
50
|
|
|
|
4072
|
return if $i < $min; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
elsif ( $seconds >= $current->[$end] ) |
208
|
|
|
|
|
|
|
{ |
209
|
2492
|
|
|
|
|
2674
|
$min = $i; |
210
|
2492
|
|
|
|
|
3861
|
my $c = int( ( $max - $i ) / 2 ); |
211
|
2492
|
|
100
|
|
|
4511
|
$c ||= 1; |
212
|
|
|
|
|
|
|
|
213
|
2492
|
|
|
|
|
2777
|
$i += $c; |
214
|
|
|
|
|
|
|
|
215
|
2492
|
100
|
|
|
|
5506
|
return if $i >= $max; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
else |
218
|
|
|
|
|
|
|
{ |
219
|
|
|
|
|
|
|
# Special case for overlapping ranges because of DST and |
220
|
|
|
|
|
|
|
# other weirdness (like Alaska's change when bought from |
221
|
|
|
|
|
|
|
# Russia by the US). Always prefer latest span. |
222
|
776
|
100
|
100
|
|
|
2693
|
if ( $current->[IS_DST] && $type eq 'local' ) |
223
|
|
|
|
|
|
|
{ |
224
|
106
|
|
|
|
|
237
|
my $next = $self->{spans}[$i + 1]; |
225
|
|
|
|
|
|
|
# Sometimes we will get here and the span we're |
226
|
|
|
|
|
|
|
# looking at is the last that's been generated so far. |
227
|
|
|
|
|
|
|
# We need to try to generate one more or else we run |
228
|
|
|
|
|
|
|
# out. |
229
|
106
|
|
66
|
|
|
373
|
$next ||= $self->_generate_next_span; |
230
|
|
|
|
|
|
|
|
231
|
106
|
50
|
|
|
|
241
|
die "No next span in $self->{max_year}" unless defined $next; |
232
|
|
|
|
|
|
|
|
233
|
106
|
50
|
33
|
|
|
683
|
if ( ( ! $next->[IS_DST] ) |
|
|
|
33
|
|
|
|
|
234
|
|
|
|
|
|
|
&& $next->[$start] <= $seconds |
235
|
|
|
|
|
|
|
&& $seconds <= $next->[$end] |
236
|
|
|
|
|
|
|
) |
237
|
|
|
|
|
|
|
{ |
238
|
0
|
|
|
|
|
0
|
return $next; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
776
|
|
|
|
|
1924
|
return $current; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
sub _generate_next_span |
248
|
|
|
|
|
|
|
{ |
249
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
250
|
|
|
|
|
|
|
|
251
|
1
|
|
|
|
|
2
|
my $last_idx = $#{ $self->{spans} }; |
|
1
|
|
|
|
|
3
|
|
252
|
|
|
|
|
|
|
|
253
|
1
|
|
|
|
|
5
|
my $max_span = $self->max_span; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
# Kind of a hack, but AFAIK there are no zones where it takes |
256
|
|
|
|
|
|
|
# _more_ than a year for a _future_ time zone change to occur, so |
257
|
|
|
|
|
|
|
# by looking two years out we can ensure that we will find at |
258
|
|
|
|
|
|
|
# least one more span. Of course, I will no doubt be proved wrong |
259
|
|
|
|
|
|
|
# and this will cause errors. |
260
|
1
|
|
|
|
|
6
|
$self->_generate_spans_until_match |
261
|
|
|
|
|
|
|
( $self->{max_year} + 2, $max_span->[UTC_END] + ( 366 * 86400 ), 'utc' ); |
262
|
|
|
|
|
|
|
|
263
|
1
|
|
|
|
|
8
|
return $self->{spans}[ $last_idx + 1 ]; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
sub _generate_spans_until_match |
267
|
|
|
|
|
|
|
{ |
268
|
16
|
|
|
16
|
|
30
|
my $self = shift; |
269
|
16
|
|
|
|
|
30
|
my $generate_until_year = shift; |
270
|
16
|
|
|
|
|
27
|
my $seconds = shift; |
271
|
16
|
|
|
|
|
29
|
my $type = shift; |
272
|
|
|
|
|
|
|
|
273
|
16
|
|
|
|
|
30
|
my @changes; |
274
|
16
|
|
|
|
|
30
|
my @rules = @{ $self->rules }; |
|
16
|
|
|
|
|
62
|
|
275
|
16
|
|
|
|
|
66
|
foreach my $year ( $self->max_year .. $generate_until_year ) |
276
|
|
|
|
|
|
|
{ |
277
|
559
|
|
|
|
|
1769
|
for ( my $x = 0; $x < @rules; $x++ ) |
278
|
|
|
|
|
|
|
{ |
279
|
1118
|
|
|
|
|
1889
|
my $last_offset_from_std; |
280
|
|
|
|
|
|
|
|
281
|
1118
|
50
|
|
|
|
2756
|
if ( @rules == 2 ) |
|
|
0
|
|
|
|
|
|
282
|
|
|
|
|
|
|
{ |
283
|
1118
|
100
|
|
|
|
5212
|
$last_offset_from_std = |
284
|
|
|
|
|
|
|
$x ? $rules[0]->offset_from_std : $rules[1]->offset_from_std; |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
elsif ( @rules == 1 ) |
287
|
|
|
|
|
|
|
{ |
288
|
0
|
|
|
|
|
0
|
$last_offset_from_std = $rules[0]->offset_from_std; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
else |
291
|
|
|
|
|
|
|
{ |
292
|
0
|
|
|
|
|
0
|
my $count = scalar @rules; |
293
|
0
|
|
|
|
|
0
|
die "Cannot generate future changes for zone with $count infinite rules\n"; |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
|
296
|
1118
|
|
|
|
|
2123
|
my $rule = $rules[$x]; |
297
|
|
|
|
|
|
|
|
298
|
1118
|
|
|
|
|
3683
|
my $next = |
299
|
|
|
|
|
|
|
$rule->utc_start_datetime_for_year |
300
|
|
|
|
|
|
|
( $year, $self->last_offset, $last_offset_from_std ); |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# don't bother with changes we've seen already |
303
|
1118
|
100
|
|
|
|
5753
|
next if $next->utc_rd_as_seconds < $self->max_span->[UTC_END]; |
304
|
|
|
|
|
|
|
|
305
|
1081
|
|
|
|
|
3811
|
my $last_observance = $self->last_observance; |
306
|
1081
|
|
|
|
|
9852
|
push @changes, |
307
|
|
|
|
|
|
|
DateTimeX::Lite::OlsonDB::Change->new |
308
|
|
|
|
|
|
|
( type => 'rule', |
309
|
|
|
|
|
|
|
utc_start_datetime => $next, |
310
|
|
|
|
|
|
|
local_start_datetime => |
311
|
|
|
|
|
|
|
$next + |
312
|
|
|
|
|
|
|
DateTimeX::Lite::Duration->new |
313
|
|
|
|
|
|
|
( seconds => $last_observance->total_offset + |
314
|
|
|
|
|
|
|
$rule->offset_from_std ), |
315
|
|
|
|
|
|
|
short_name => |
316
|
|
|
|
|
|
|
sprintf( $last_observance->format, $rule->letter ), |
317
|
|
|
|
|
|
|
observance => $last_observance, |
318
|
|
|
|
|
|
|
rule => $rule, |
319
|
|
|
|
|
|
|
); |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
16
|
|
|
|
|
58
|
$self->{max_year} = $generate_until_year; |
324
|
|
|
|
|
|
|
|
325
|
16
|
|
|
|
|
205
|
my @sorted = sort { $a->utc_start_datetime <=> $b->utc_start_datetime } @changes; |
|
1910
|
|
|
|
|
5654
|
|
326
|
|
|
|
|
|
|
|
327
|
16
|
|
|
|
|
78
|
my ( $start, $end ) = _keys_for_type($type); |
328
|
|
|
|
|
|
|
|
329
|
16
|
|
|
|
|
33
|
my $match; |
330
|
16
|
|
|
|
|
76
|
for ( my $x = 1; $x < @sorted; $x++ ) |
331
|
|
|
|
|
|
|
{ |
332
|
1065
|
100
|
|
|
|
4088
|
my $last_total_offset = |
333
|
|
|
|
|
|
|
$x == 1 ? $self->max_span->[OFFSET] : $sorted[ $x - 2 ]->total_offset; |
334
|
|
|
|
|
|
|
|
335
|
1065
|
|
|
|
|
3142
|
my $span = |
336
|
|
|
|
|
|
|
DateTimeX::Lite::OlsonDB::Change::two_changes_as_span |
337
|
|
|
|
|
|
|
( @sorted[ $x - 1, $x ], $last_total_offset ); |
338
|
|
|
|
|
|
|
|
339
|
1065
|
|
|
|
|
2181
|
$span = _span_as_array($span); |
340
|
|
|
|
|
|
|
|
341
|
1065
|
|
|
|
|
2125
|
push @{ $self->{spans} }, $span; |
|
1065
|
|
|
|
|
2088
|
|
342
|
|
|
|
|
|
|
|
343
|
1065
|
100
|
100
|
|
|
7114
|
$match = $span |
344
|
|
|
|
|
|
|
if $seconds >= $span->[$start] && $seconds < $span->[$end]; |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
16
|
|
|
|
|
10139
|
return $match; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
1933
|
|
|
1933
|
0
|
9418
|
sub max_span { $_[0]->{spans}[-1] } |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
sub _keys_for_type |
353
|
|
|
|
|
|
|
{ |
354
|
799
|
100
|
|
799
|
|
2532
|
$_[0] eq 'utc' ? ( UTC_START, UTC_END ) : ( LOCAL_START, LOCAL_END ); |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
sub _span_as_array |
358
|
|
|
|
|
|
|
{ |
359
|
1065
|
|
|
1065
|
|
1396
|
[ @{ $_[0] }{ qw( utc_start utc_end local_start local_end offset is_dst short_name ) } ]; |
|
1065
|
|
|
|
|
4340
|
|
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
33278
|
|
|
33278
|
1
|
114032
|
sub is_floating { 0 } |
363
|
|
|
|
|
|
|
|
364
|
772
|
|
|
772
|
1
|
4131
|
sub is_utc { 0 } |
365
|
|
|
|
|
|
|
|
366
|
55
|
|
|
55
|
1
|
301
|
sub has_dst_changes { $_[0]->{has_dst_changes} } |
367
|
|
|
|
|
|
|
|
368
|
1110
|
|
|
1110
|
1
|
471823
|
sub name { $_[0]->{name} } |
369
|
0
|
|
|
0
|
1
|
0
|
sub category { (split /\//, $_[0]->{name}, 2)[0] } |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub is_valid_name |
372
|
|
|
|
|
|
|
{ |
373
|
13
|
|
|
13
|
1
|
16594
|
my $tz; |
374
|
|
|
|
|
|
|
{ |
375
|
13
|
|
|
|
|
24
|
local $@; |
|
13
|
|
|
|
|
17
|
|
376
|
13
|
|
|
|
|
24
|
$tz = eval { $_[0]->load( name => $_[1] ) }; |
|
13
|
|
|
|
|
49
|
|
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
13
|
100
|
66
|
|
|
169
|
return $tz && $tz->isa('DateTimeX::Lite::TimeZone') ? 1 : 0 |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
# |
383
|
|
|
|
|
|
|
# Functions |
384
|
|
|
|
|
|
|
# |
385
|
|
|
|
|
|
|
sub offset_as_seconds { |
386
|
|
|
|
|
|
|
{ |
387
|
224
|
|
|
224
|
1
|
4909
|
local $@; |
|
224
|
|
|
|
|
277
|
|
388
|
224
|
100
|
|
|
|
562
|
shift if eval { $_[0]->isa('DateTimeX::Lite::TimeZone') }; |
|
224
|
|
|
|
|
2196
|
|
389
|
|
|
|
|
|
|
} |
390
|
224
|
|
|
|
|
778
|
DateTimeX::Lite::Util::offset_as_seconds(@_); |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
sub offset_as_string { |
394
|
|
|
|
|
|
|
{ |
395
|
74
|
|
|
74
|
1
|
4905
|
local $@; |
|
74
|
|
|
|
|
112
|
|
396
|
74
|
100
|
|
|
|
122
|
shift if eval { $_[0]->isa('DateTimeX::Lite::TimeZone') }; |
|
74
|
|
|
|
|
664
|
|
397
|
|
|
|
|
|
|
} |
398
|
74
|
|
|
|
|
286
|
DateTimeX::Lite::Util::offset_as_string(@_); |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
# These methods all operate on data contained in the DateTime/TimeZone/Catalog.pm file. |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
sub all_names { |
404
|
4
|
100
|
|
4
|
1
|
17642
|
return wantarray ? @DateTimeX::Lite::TimeZone::Catalog::ALL : [@DateTimeX::Lite::TimeZone::Catalog::ALL]; |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
sub categories { |
408
|
|
|
|
|
|
|
return wantarray |
409
|
|
|
|
|
|
|
? @DateTimeX::Lite::TimeZone::Catalog::CATEGORY_NAMES |
410
|
2
|
100
|
|
2
|
1
|
3579
|
: [@DateTimeX::Lite::TimeZone::Catalog::CATEGORY_NAMES]; |
411
|
|
|
|
|
|
|
} |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
sub links |
414
|
|
|
|
|
|
|
{ |
415
|
|
|
|
|
|
|
return |
416
|
5
|
100
|
|
5
|
1
|
2616
|
wantarray ? %DateTimeX::Lite::TimeZone::Catalog::LINKS : {%DateTimeX::Lite::TimeZone::Catalog::LINKS}; |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
sub names_in_category |
420
|
|
|
|
|
|
|
{ |
421
|
3
|
100
|
|
3
|
1
|
1214
|
shift if $_[0]->isa('DateTimeX::Lite::TimeZone'); |
422
|
3
|
50
|
|
|
|
10
|
return unless exists $DateTimeX::Lite::TimeZone::Catalog::CATEGORIES{ $_[0] }; |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
return |
425
|
|
|
|
|
|
|
wantarray |
426
|
3
|
100
|
|
|
|
9
|
? @{ $DateTimeX::Lite::TimeZone::Catalog::CATEGORIES{ $_[0] } } |
|
2
|
|
|
|
|
48
|
|
427
|
|
|
|
|
|
|
: [ $DateTimeX::Lite::TimeZone::Catalog::CATEGORIES{ $_[0] } ]; |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
sub countries |
431
|
|
|
|
|
|
|
{ |
432
|
|
|
|
|
|
|
wantarray |
433
|
1
|
50
|
|
1
|
1
|
931
|
? ( sort keys %DateTimeX::Lite::TimeZone::Catalog::ZONES_BY_COUNTRY ) |
434
|
|
|
|
|
|
|
: [ sort keys %DateTimeX::Lite::TimeZone::Catalog::ZONES_BY_COUNTRY ]; |
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
sub names_in_country |
438
|
|
|
|
|
|
|
{ |
439
|
5
|
100
|
|
5
|
1
|
3863
|
shift if $_[0]->isa('DateTimeX::Lite::TimeZone'); |
440
|
|
|
|
|
|
|
|
441
|
5
|
50
|
|
|
|
17
|
return unless exists $DateTimeX::Lite::TimeZone::Catalog::ZONES_BY_COUNTRY{ lc $_[0] }; |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
return |
444
|
|
|
|
|
|
|
wantarray |
445
|
5
|
100
|
|
|
|
15
|
? @{ $DateTimeX::Lite::TimeZone::Catalog::ZONES_BY_COUNTRY{ lc $_[0] } } |
|
4
|
|
|
|
|
25
|
|
446
|
|
|
|
|
|
|
: $DateTimeX::Lite::TimeZone::Catalog::ZONES_BY_COUNTRY{ lc $_[0] }; |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
1; |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
__END__ |