← Index
NYTProf Performance Profile   « line view »
For svc/members/upsert
  Run on Tue Jan 13 11:50:22 2015
Reported on Tue Jan 13 12:09:47 2015

Filename/usr/share/perl5/DateTime/TimeZone.pm
StatementsExecuted 50 statements in 6.37ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
1113.91ms4.00msDateTime::TimeZone::::BEGIN@10DateTime::TimeZone::BEGIN@10
1112.13ms27.3msDateTime::TimeZone::::BEGIN@12DateTime::TimeZone::BEGIN@12
1111.30ms18.1msDateTime::TimeZone::::BEGIN@11DateTime::TimeZone::BEGIN@11
22146µs86µsDateTime::TimeZone::::newDateTime::TimeZone::new
11118µs18µsDateTime::TimeZone::::BEGIN@5DateTime::TimeZone::BEGIN@5
11114µs68µsDateTime::TimeZone::::BEGIN@15DateTime::TimeZone::BEGIN@15
1119µs14µsDateTime::TimeZone::::BEGIN@8DateTime::TimeZone::BEGIN@8
1118µs8µsDateTime::TimeZone::::BEGIN@13DateTime::TimeZone::BEGIN@13
1117µs19µsDateTime::TimeZone::::BEGIN@7DateTime::TimeZone::BEGIN@7
1116µs45µsDateTime::TimeZone::::BEGIN@17DateTime::TimeZone::BEGIN@17
1116µs6µsDateTime::TimeZone::::BEGIN@14DateTime::TimeZone::BEGIN@14
1116µs28µsDateTime::TimeZone::::BEGIN@25DateTime::TimeZone::BEGIN@25
1116µs32µsDateTime::TimeZone::::BEGIN@18DateTime::TimeZone::BEGIN@18
1116µs29µsDateTime::TimeZone::::BEGIN@24DateTime::TimeZone::BEGIN@24
1116µs28µsDateTime::TimeZone::::BEGIN@21DateTime::TimeZone::BEGIN@21
1116µs66µsDateTime::TimeZone::::BEGIN@23DateTime::TimeZone::BEGIN@23
1116µs26µsDateTime::TimeZone::::BEGIN@26DateTime::TimeZone::BEGIN@26
1115µs28µsDateTime::TimeZone::::BEGIN@22DateTime::TimeZone::BEGIN@22
1115µs26µsDateTime::TimeZone::::BEGIN@27DateTime::TimeZone::BEGIN@27
2113µs3µsDateTime::TimeZone::::CORE:matchDateTime::TimeZone::CORE:match (opcode)
0000s0sDateTime::TimeZone::::STORABLE_freezeDateTime::TimeZone::STORABLE_freeze
0000s0sDateTime::TimeZone::::STORABLE_thawDateTime::TimeZone::STORABLE_thaw
0000s0sDateTime::TimeZone::::_generate_next_spanDateTime::TimeZone::_generate_next_span
0000s0sDateTime::TimeZone::::_generate_spans_until_matchDateTime::TimeZone::_generate_spans_until_match
0000s0sDateTime::TimeZone::::_initDateTime::TimeZone::_init
0000s0sDateTime::TimeZone::::_keys_for_typeDateTime::TimeZone::_keys_for_type
0000s0sDateTime::TimeZone::::_span_as_arrayDateTime::TimeZone::_span_as_array
0000s0sDateTime::TimeZone::::_span_for_datetimeDateTime::TimeZone::_span_for_datetime
0000s0sDateTime::TimeZone::::_spans_binary_searchDateTime::TimeZone::_spans_binary_search
0000s0sDateTime::TimeZone::::all_namesDateTime::TimeZone::all_names
0000s0sDateTime::TimeZone::::categoriesDateTime::TimeZone::categories
0000s0sDateTime::TimeZone::::categoryDateTime::TimeZone::category
0000s0sDateTime::TimeZone::::countriesDateTime::TimeZone::countries
0000s0sDateTime::TimeZone::::has_dst_changesDateTime::TimeZone::has_dst_changes
0000s0sDateTime::TimeZone::::is_dst_for_datetimeDateTime::TimeZone::is_dst_for_datetime
0000s0sDateTime::TimeZone::::is_floatingDateTime::TimeZone::is_floating
0000s0sDateTime::TimeZone::::is_olsonDateTime::TimeZone::is_olson
0000s0sDateTime::TimeZone::::is_utcDateTime::TimeZone::is_utc
0000s0sDateTime::TimeZone::::is_valid_nameDateTime::TimeZone::is_valid_name
0000s0sDateTime::TimeZone::::linksDateTime::TimeZone::links
0000s0sDateTime::TimeZone::::max_spanDateTime::TimeZone::max_span
0000s0sDateTime::TimeZone::::nameDateTime::TimeZone::name
0000s0sDateTime::TimeZone::::names_in_categoryDateTime::TimeZone::names_in_category
0000s0sDateTime::TimeZone::::names_in_countryDateTime::TimeZone::names_in_country
0000s0sDateTime::TimeZone::::offset_as_secondsDateTime::TimeZone::offset_as_seconds
0000s0sDateTime::TimeZone::::offset_as_stringDateTime::TimeZone::offset_as_string
0000s0sDateTime::TimeZone::::offset_for_datetimeDateTime::TimeZone::offset_for_datetime
0000s0sDateTime::TimeZone::::offset_for_local_datetimeDateTime::TimeZone::offset_for_local_datetime
0000s0sDateTime::TimeZone::::short_name_for_datetimeDateTime::TimeZone::short_name_for_datetime
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package DateTime::TimeZone;
2# git description: v1.74-3-g53bc6be
31800ns$DateTime::TimeZone::VERSION = '1.75';
4
5248µs118µs
# spent 18µs within DateTime::TimeZone::BEGIN@5 which was called: # once (18µs+0s) by C4::Context::BEGIN@106 at line 5
use 5.006;
# spent 18µs making 1 call to DateTime::TimeZone::BEGIN@5
6
7225µs232µs
# spent 19µs (7+12) within DateTime::TimeZone::BEGIN@7 which was called: # once (7µs+12µs) by C4::Context::BEGIN@106 at line 7
use strict;
# spent 19µs making 1 call to DateTime::TimeZone::BEGIN@7 # spent 12µs making 1 call to strict::import
8224µs220µs
# spent 14µs (9+5) within DateTime::TimeZone::BEGIN@8 which was called: # once (9µs+5µs) by C4::Context::BEGIN@106 at line 8
use warnings;
# spent 14µs making 1 call to DateTime::TimeZone::BEGIN@8 # spent 5µs making 1 call to warnings::import
9
1021.08ms14.00ms
# spent 4.00ms (3.91+91µs) within DateTime::TimeZone::BEGIN@10 which was called: # once (3.91ms+91µs) by C4::Context::BEGIN@106 at line 10
use DateTime::TimeZone::Catalog;
# spent 4.00ms making 1 call to DateTime::TimeZone::BEGIN@10
1121.14ms118.1ms
# spent 18.1ms (1.30+16.8) within DateTime::TimeZone::BEGIN@11 which was called: # once (1.30ms+16.8ms) by C4::Context::BEGIN@106 at line 11
use DateTime::TimeZone::Floating;
# spent 18.1ms making 1 call to DateTime::TimeZone::BEGIN@11
1221.57ms127.3ms
# spent 27.3ms (2.13+25.2) within DateTime::TimeZone::BEGIN@12 which was called: # once (2.13ms+25.2ms) by C4::Context::BEGIN@106 at line 12
use DateTime::TimeZone::Local;
# spent 27.3ms making 1 call to DateTime::TimeZone::BEGIN@12
13225µs18µs
# spent 8µs within DateTime::TimeZone::BEGIN@13 which was called: # once (8µs+0s) by C4::Context::BEGIN@106 at line 13
use DateTime::TimeZone::OffsetOnly;
# spent 8µs making 1 call to DateTime::TimeZone::BEGIN@13
14232µs16µs
# spent 6µs within DateTime::TimeZone::BEGIN@14 which was called: # once (6µs+0s) by C4::Context::BEGIN@106 at line 14
use DateTime::TimeZone::UTC;
# spent 6µs making 1 call to DateTime::TimeZone::BEGIN@14
15366µs3123µs
# spent 68µs (14+55) within DateTime::TimeZone::BEGIN@15 which was called: # once (14µs+55µs) by C4::Context::BEGIN@106 at line 15
use Params::Validate 0.72 qw( validate validate_pos SCALAR ARRAYREF BOOLEAN );
# spent 68µs making 1 call to DateTime::TimeZone::BEGIN@15 # spent 44µs making 1 call to Exporter::import # spent 10µs making 1 call to UNIVERSAL::VERSION
16
17237µs284µs
# spent 45µs (6+39) within DateTime::TimeZone::BEGIN@17 which was called: # once (6µs+39µs) by C4::Context::BEGIN@106 at line 17
use constant INFINITY => 100**1000;
# spent 45µs making 1 call to DateTime::TimeZone::BEGIN@17 # spent 39µs making 1 call to constant::import
18228µs258µs
# spent 32µs (6+26) within DateTime::TimeZone::BEGIN@18 which was called: # once (6µs+26µs) by C4::Context::BEGIN@106 at line 18
use constant NEG_INFINITY => -1 * ( 100**1000 );
# spent 32µs making 1 call to DateTime::TimeZone::BEGIN@18 # spent 26µs making 1 call to constant::import
19
20# the offsets for each span element
21224µs251µs
# spent 28µs (6+22) within DateTime::TimeZone::BEGIN@21 which was called: # once (6µs+22µs) by C4::Context::BEGIN@106 at line 21
use constant UTC_START => 0;
# spent 28µs making 1 call to DateTime::TimeZone::BEGIN@21 # spent 22µs making 1 call to constant::import
22225µs251µs
# spent 28µs (5+23) within DateTime::TimeZone::BEGIN@22 which was called: # once (5µs+23µs) by C4::Context::BEGIN@106 at line 22
use constant UTC_END => 1;
# spent 28µs making 1 call to DateTime::TimeZone::BEGIN@22 # spent 23µs making 1 call to constant::import
23227µs2127µs
# spent 66µs (6+61) within DateTime::TimeZone::BEGIN@23 which was called: # once (6µs+61µs) by C4::Context::BEGIN@106 at line 23
use constant LOCAL_START => 2;
# spent 66µs making 1 call to DateTime::TimeZone::BEGIN@23 # spent 61µs making 1 call to constant::import
24224µs251µs
# spent 29µs (6+23) within DateTime::TimeZone::BEGIN@24 which was called: # once (6µs+23µs) by C4::Context::BEGIN@106 at line 24
use constant LOCAL_END => 3;
# spent 29µs making 1 call to DateTime::TimeZone::BEGIN@24 # spent 23µs making 1 call to constant::import
25224µs250µs
# spent 28µs (6+22) within DateTime::TimeZone::BEGIN@25 which was called: # once (6µs+22µs) by C4::Context::BEGIN@106 at line 25
use constant OFFSET => 4;
# spent 28µs making 1 call to DateTime::TimeZone::BEGIN@25 # spent 22µs making 1 call to constant::import
26223µs246µs
# spent 26µs (6+20) within DateTime::TimeZone::BEGIN@26 which was called: # once (6µs+20µs) by C4::Context::BEGIN@106 at line 26
use constant IS_DST => 5;
# spent 26µs making 1 call to DateTime::TimeZone::BEGIN@26 # spent 20µs making 1 call to constant::import
2722.06ms247µs
# spent 26µs (5+21) within DateTime::TimeZone::BEGIN@27 which was called: # once (5µs+21µs) by C4::Context::BEGIN@106 at line 27
use constant SHORT_NAME => 6;
# spent 26µs making 1 call to DateTime::TimeZone::BEGIN@27 # spent 21µs making 1 call to constant::import
28
2918µsmy %SpecialName = map { $_ => 1 }
30 qw( EST MST HST CET EET MET WET EST5EDT CST6CDT MST7MDT PST8PDT );
31
32
# spent 86µs (46+39) within DateTime::TimeZone::new which was called 2 times, avg 43µs/call: # once (30µs+24µs) by C4::Circulation::BEGIN@24 at line 44 of DateTime/Infinite.pm # once (16µs+15µs) by C4::Circulation::BEGIN@24 at line 69 of DateTime/Infinite.pm
sub new {
332900ns my $class = shift;
34234µs218µs my %p = validate(
# spent 18µs making 2 calls to Params::Validate::XS::validate, avg 9µs/call
35 @_,
36 { name => { type => SCALAR } },
37 );
38
3925µs if ( exists $DateTime::TimeZone::Catalog::LINKS{ $p{name} } ) {
40 $p{name} = $DateTime::TimeZone::Catalog::LINKS{ $p{name} };
41 }
42 elsif ( exists $DateTime::TimeZone::Catalog::LINKS{ uc $p{name} } ) {
43 $p{name} = $DateTime::TimeZone::Catalog::LINKS{ uc $p{name} };
44 }
45
46210µs23µs unless ( $p{name} =~ m,/,
# spent 3µs making 2 calls to DateTime::TimeZone::CORE:match, avg 2µs/call
47 || $SpecialName{ $p{name} } ) {
48217µs218µs if ( $p{name} eq 'floating' ) {
# spent 18µs making 2 calls to Class::Singleton::instance, avg 9µs/call
49 return DateTime::TimeZone::Floating->instance;
50 }
51
52 if ( $p{name} eq 'local' ) {
53 return DateTime::TimeZone::Local->TimeZone();
54 }
55
56 if ( $p{name} eq 'UTC' || $p{name} eq 'Z' ) {
57 return DateTime::TimeZone::UTC->instance;
58 }
59
60 return DateTime::TimeZone::OffsetOnly->new( offset => $p{name} );
61 }
62
63 my $subclass = $p{name};
64 $subclass =~ s/-/_/g;
65 $subclass =~ s{/}{::}g;
66 my $real_class = "DateTime::TimeZone::$subclass";
67
68 die "The timezone '$p{name}' in an invalid name.\n"
69 unless $real_class =~ /^\w+(::\w+)*$/;
70
71 unless ( $real_class->can('instance') ) {
72 ($real_class) = $real_class =~ m{\A([a-zA-Z0-9_]+(?:::[a-zA-Z0-9_]+)*)\z};
73
74 my $e = do {
75 local $@;
76 local $SIG{__DIE__};
77 eval "require $real_class";
78 $@;
79 };
80
81 if ($e) {
82 my $regex = join '.', split /::/, $real_class;
83 $regex .= '\\.pm';
84
85 if ( $e =~ /^Can't locate $regex/i ) {
86 die
87 "The timezone '$p{name}' could not be loaded, or is an invalid name.\n";
88 }
89 else {
90 die $e;
91 }
92 }
93 }
94
95 my $zone = $real_class->instance( name => $p{name}, is_olson => 1 );
96
97 if ( $zone->is_olson() ) {
98 my $object_version
99 = $zone->can('olson_version')
100 ? $zone->olson_version()
101 : 'unknown';
102 my $catalog_version = DateTime::TimeZone::Catalog->OlsonVersion();
103
104 if ( $object_version ne $catalog_version ) {
105 warn
106 "Loaded $real_class, which is from an older version ($object_version) of the Olson database than this installation of DateTime::TimeZone ($catalog_version).\n";
107 }
108 }
109
110 return $zone;
111}
112
113sub _init {
114 my $class = shift;
115 my %p = validate(
116 @_, {
117 name => { type => SCALAR },
118 spans => { type => ARRAYREF },
119 is_olson => { type => BOOLEAN, default => 0 },
120 },
121 );
122
123 my $self = bless {
124 name => $p{name},
125 spans => $p{spans},
126 is_olson => $p{is_olson},
127 }, $class;
128
129 foreach my $k (qw( last_offset last_observance rules max_year )) {
130 my $m = "_$k";
131 $self->{$k} = $self->$m() if $self->can($m);
132 }
133
134 return $self;
135}
136
137sub is_olson { $_[0]->{is_olson} }
138
139sub is_dst_for_datetime {
140 my $self = shift;
141
142 my $span = $self->_span_for_datetime( 'utc', $_[0] );
143
144 return $span->[IS_DST];
145}
146
147sub offset_for_datetime {
148 my $self = shift;
149
150 my $span = $self->_span_for_datetime( 'utc', $_[0] );
151
152 return $span->[OFFSET];
153}
154
155sub offset_for_local_datetime {
156 my $self = shift;
157
158 my $span = $self->_span_for_datetime( 'local', $_[0] );
159
160 return $span->[OFFSET];
161}
162
163sub short_name_for_datetime {
164 my $self = shift;
165
166 my $span = $self->_span_for_datetime( 'utc', $_[0] );
167
168 return $span->[SHORT_NAME];
169}
170
171sub _span_for_datetime {
172 my $self = shift;
173 my $type = shift;
174 my $dt = shift;
175
176 my $method = $type . '_rd_as_seconds';
177
178 my $end = $type eq 'utc' ? UTC_END : LOCAL_END;
179
180 my $span;
181 my $seconds = $dt->$method();
182 if ( $seconds < $self->max_span->[$end] ) {
183 $span = $self->_spans_binary_search( $type, $seconds );
184 }
185 else {
186 my $until_year = $dt->utc_year + 1;
187 $span = $self->_generate_spans_until_match( $until_year, $seconds,
188 $type );
189 }
190
191 # This means someone gave a local time that doesn't exist
192 # (like during a transition into savings time)
193 unless ( defined $span ) {
194 my $err = 'Invalid local time for date';
195 $err .= ' ' . $dt->iso8601 if $type eq 'utc';
196 $err .= " in time zone: " . $self->name;
197 $err .= "\n";
198
199 die $err;
200 }
201
202 return $span;
203}
204
205sub _spans_binary_search {
206 my $self = shift;
207 my ( $type, $seconds ) = @_;
208
209 my ( $start, $end ) = _keys_for_type($type);
210
211 my $min = 0;
212 my $max = scalar @{ $self->{spans} } + 1;
213 my $i = int( $max / 2 );
214
215 # special case for when there are only 2 spans
216 $i++ if $max % 2 && $max != 3;
217
218 $i = 0 if @{ $self->{spans} } == 1;
219
220 while (1) {
221 my $current = $self->{spans}[$i];
222
223 if ( $seconds < $current->[$start] ) {
224 $max = $i;
225 my $c = int( ( $i - $min ) / 2 );
226 $c ||= 1;
227
228 $i -= $c;
229
230 return if $i < $min;
231 }
232 elsif ( $seconds >= $current->[$end] ) {
233 $min = $i;
234 my $c = int( ( $max - $i ) / 2 );
235 $c ||= 1;
236
237 $i += $c;
238
239 return if $i >= $max;
240 }
241 else {
242
243 # Special case for overlapping ranges because of DST and
244 # other weirdness (like Alaska's change when bought from
245 # Russia by the US). Always prefer latest span.
246 if ( $current->[IS_DST] && $type eq 'local' ) {
247
248 # Asia/Dhaka in 2009j goes into DST without any known
249 # end-of-DST date (wtf, Bangladesh).
250 return $current if $current->[UTC_END] == INFINITY;
251
252 my $next = $self->{spans}[ $i + 1 ];
253
254 # Sometimes we will get here and the span we're
255 # looking at is the last that's been generated so far.
256 # We need to try to generate one more or else we run
257 # out.
258 $next ||= $self->_generate_next_span;
259
260 die "No next span in $self->{max_year}" unless defined $next;
261
262 if ( ( !$next->[IS_DST] )
263 && $next->[$start] <= $seconds
264 && $seconds <= $next->[$end] ) {
265 return $next;
266 }
267 }
268
269 return $current;
270 }
271 }
272}
273
274sub _generate_next_span {
275 my $self = shift;
276
277 my $last_idx = $#{ $self->{spans} };
278
279 my $max_span = $self->max_span;
280
281 # Kind of a hack, but AFAIK there are no zones where it takes
282 # _more_ than a year for a _future_ time zone change to occur, so
283 # by looking two years out we can ensure that we will find at
284 # least one more span. Of course, I will no doubt be proved wrong
285 # and this will cause errors.
286 $self->_generate_spans_until_match( $self->{max_year} + 2,
287 $max_span->[UTC_END] + ( 366 * 86400 ), 'utc' );
288
289 return $self->{spans}[ $last_idx + 1 ];
290}
291
292sub _generate_spans_until_match {
293 my $self = shift;
294 my $generate_until_year = shift;
295 my $seconds = shift;
296 my $type = shift;
297
298 my @changes;
299 my @rules = @{ $self->_rules };
300 foreach my $year ( $self->{max_year} .. $generate_until_year ) {
301 for ( my $x = 0; $x < @rules; $x++ ) {
302 my $last_offset_from_std;
303
304 if ( @rules == 2 ) {
305 $last_offset_from_std
306 = $x
307 ? $rules[0]->offset_from_std
308 : $rules[1]->offset_from_std;
309 }
310 elsif ( @rules == 1 ) {
311 $last_offset_from_std = $rules[0]->offset_from_std;
312 }
313 else {
314 my $count = scalar @rules;
315 die
316 "Cannot generate future changes for zone with $count infinite rules\n";
317 }
318
319 my $rule = $rules[$x];
320
321 my $next = $rule->utc_start_datetime_for_year( $year,
322 $self->{last_offset}, $last_offset_from_std );
323
324 # don't bother with changes we've seen already
325 next if $next->utc_rd_as_seconds < $self->max_span->[UTC_END];
326
327 push @changes,
328 DateTime::TimeZone::OlsonDB::Change->new(
329 type => 'rule',
330 utc_start_datetime => $next,
331 local_start_datetime => $next + DateTime::Duration->new(
332 seconds => $self->{last_observance}->total_offset
333 + $rule->offset_from_std
334 ),
335 short_name => sprintf(
336 $self->{last_observance}->format, $rule->letter
337 ),
338 observance => $self->{last_observance},
339 rule => $rule,
340 );
341 }
342 }
343
344 $self->{max_year} = $generate_until_year;
345
346 my @sorted
347 = sort { $a->utc_start_datetime <=> $b->utc_start_datetime } @changes;
348
349 my ( $start, $end ) = _keys_for_type($type);
350
351 my $match;
352 for ( my $x = 1; $x < @sorted; $x++ ) {
353 my $last_total_offset
354 = $x == 1
355 ? $self->max_span->[OFFSET]
356 : $sorted[ $x - 2 ]->total_offset;
357
358 my $span = DateTime::TimeZone::OlsonDB::Change::two_changes_as_span(
359 @sorted[ $x - 1, $x ], $last_total_offset );
360
361 $span = _span_as_array($span);
362
363 push @{ $self->{spans} }, $span;
364
365 $match = $span
366 if $seconds >= $span->[$start] && $seconds < $span->[$end];
367 }
368
369 return $match;
370}
371
372sub max_span { $_[0]->{spans}[-1] }
373
374sub _keys_for_type {
375 $_[0] eq 'utc' ? ( UTC_START, UTC_END ) : ( LOCAL_START, LOCAL_END );
376}
377
378sub _span_as_array {
379 [
380 @{ $_[0] }{
381 qw( utc_start utc_end local_start local_end offset is_dst short_name )
382 }
383 ];
384}
385
386sub is_floating {0}
387
388sub is_utc {0}
389
390sub has_dst_changes {0}
391
392sub name { $_[0]->{name} }
393sub category { ( split /\//, $_[0]->{name}, 2 )[0] }
394
395sub is_valid_name {
396 my $tz;
397 {
398 local $@;
399 local $SIG{__DIE__};
400 $tz = eval { $_[0]->new( name => $_[1] ) };
401 }
402
403 return $tz && $tz->isa('DateTime::TimeZone') ? 1 : 0;
404}
405
406sub STORABLE_freeze {
407 my $self = shift;
408
409 return $self->name;
410}
411
412sub STORABLE_thaw {
413 my $self = shift;
414 my $cloning = shift;
415 my $serialized = shift;
416
417 my $class = ref $self || $self;
418
419 my $obj;
420 if ( $class->isa(__PACKAGE__) ) {
421 $obj = __PACKAGE__->new( name => $serialized );
422 }
423 else {
424 $obj = $class->new( name => $serialized );
425 }
426
427 %$self = %$obj;
428
429 return $self;
430}
431
432#
433# Functions
434#
435sub offset_as_seconds {
436 {
437 local $@;
438 local $SIG{__DIE__};
439 shift if eval { $_[0]->isa('DateTime::TimeZone') };
440 }
441
442 my $offset = shift;
443
444 return undef unless defined $offset;
445
446 return 0 if $offset eq '0';
447
448 my ( $sign, $hours, $minutes, $seconds );
449 if ( $offset =~ /^([\+\-])?(\d\d?):(\d\d)(?::(\d\d))?$/ ) {
450 ( $sign, $hours, $minutes, $seconds ) = ( $1, $2, $3, $4 );
451 }
452 elsif ( $offset =~ /^([\+\-])?(\d\d)(\d\d)(\d\d)?$/ ) {
453 ( $sign, $hours, $minutes, $seconds ) = ( $1, $2, $3, $4 );
454 }
455 else {
456 return undef;
457 }
458
459 $sign = '+' unless defined $sign;
460 return undef unless $hours >= 0 && $hours <= 99;
461 return undef unless $minutes >= 0 && $minutes <= 59;
462 return undef
463 unless !defined($seconds) || ( $seconds >= 0 && $seconds <= 59 );
464
465 my $total = $hours * 3600 + $minutes * 60;
466 $total += $seconds if $seconds;
467 $total *= -1 if $sign eq '-';
468
469 return $total;
470}
471
472sub offset_as_string {
473 {
474 local $@;
475 local $SIG{__DIE__};
476 shift if eval { $_[0]->isa('DateTime::TimeZone') };
477 }
478
479 my $offset = shift;
480
481 return undef unless defined $offset;
482 return undef unless $offset >= -359999 && $offset <= 359999;
483
484 my $sign = $offset < 0 ? '-' : '+';
485
486 $offset = abs($offset);
487
488 my $hours = int( $offset / 3600 );
489 $offset %= 3600;
490 my $mins = int( $offset / 60 );
491 $offset %= 60;
492 my $secs = int($offset);
493
494 return (
495 $secs
496 ? sprintf( '%s%02d%02d%02d', $sign, $hours, $mins, $secs )
497 : sprintf( '%s%02d%02d', $sign, $hours, $mins )
498 );
499}
500
501# These methods all operate on data contained in the DateTime/TimeZone/Catalog.pm file.
502
503sub all_names {
504 return
505 wantarray
506 ? @DateTime::TimeZone::Catalog::ALL
507 : [@DateTime::TimeZone::Catalog::ALL];
508}
509
510sub categories {
511 return wantarray
512 ? @DateTime::TimeZone::Catalog::CATEGORY_NAMES
513 : [@DateTime::TimeZone::Catalog::CATEGORY_NAMES];
514}
515
516sub links {
517 return
518 wantarray
519 ? %DateTime::TimeZone::Catalog::LINKS
520 : {%DateTime::TimeZone::Catalog::LINKS};
521}
522
523sub names_in_category {
524 shift if $_[0]->isa('DateTime::TimeZone');
525 return unless exists $DateTime::TimeZone::Catalog::CATEGORIES{ $_[0] };
526
527 return wantarray
528 ? @{ $DateTime::TimeZone::Catalog::CATEGORIES{ $_[0] } }
529 : $DateTime::TimeZone::Catalog::CATEGORIES{ $_[0] };
530}
531
532sub countries {
533 wantarray
534 ? ( sort keys %DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY )
535 : [ sort keys %DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY ];
536}
537
538sub names_in_country {
539 shift if $_[0]->isa('DateTime::TimeZone');
540
541 return
542 unless
543 exists $DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY{ lc $_[0] };
544
545 return
546 wantarray
547 ? @{ $DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY{ lc $_[0] } }
548 : $DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY{ lc $_[0] };
549}
550
55114µs1;
552
553# ABSTRACT: Time zone object base class and factory
554
555__END__
 
# spent 3µs within DateTime::TimeZone::CORE:match which was called 2 times, avg 2µs/call: # 2 times (3µs+0s) by DateTime::TimeZone::new at line 46, avg 2µs/call
sub DateTime::TimeZone::CORE:match; # opcode