← Index
NYTProf Performance Profile   « block view • line view • sub view »
For 05.Domain_and_Item.t
  Run on Tue May 4 17:21:41 2010
Reported on Tue May 4 17:23:09 2010

File /usr/local/lib/perl5/site_perl/5.10.1/DateTime/TimeZone.pm
Statements Executed 1077
Statement Execution Time 7.18ms
Subroutines — ordered by exclusive time
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
1112.52ms2.61msDateTime::TimeZone::::BEGIN@10DateTime::TimeZone::BEGIN@10
63541.54ms20.4msDateTime::TimeZone::::newDateTime::TimeZone::new
111418µs484µsDateTime::TimeZone::::BEGIN@12DateTime::TimeZone::BEGIN@12
1711319µs1.47msDateTime::TimeZone::::STORABLE_thawDateTime::TimeZone::STORABLE_thaw
1011265µs308µsDateTime::TimeZone::::offset_as_secondsDateTime::TimeZone::offset_as_seconds
111237µs1.30msDateTime::TimeZone::::BEGIN@11DateTime::TimeZone::BEGIN@11
811182µs200µsDateTime::TimeZone::::offset_as_stringDateTime::TimeZone::offset_as_string
10851129µs129µsDateTime::TimeZone::::is_floatingDateTime::TimeZone::is_floating
8322109µs109µsDateTime::TimeZone::::CORE:matchDateTime::TimeZone::CORE:match (opcode)
111166µs93µsDateTime::TimeZone::::STORABLE_freezeDateTime::TimeZone::STORABLE_freeze
132233µs33µsDateTime::TimeZone::::nameDateTime::TimeZone::name
11125µs25µsDateTime::TimeZone::::BEGIN@3DateTime::TimeZone::BEGIN@3
11110µs64µsDateTime::TimeZone::::BEGIN@17DateTime::TimeZone::BEGIN@17
11110µs17µsDateTime::TimeZone::::BEGIN@5DateTime::TimeZone::BEGIN@5
11110µs49µsDateTime::TimeZone::::BEGIN@27DateTime::TimeZone::BEGIN@27
1119µs29µsDateTime::TimeZone::::BEGIN@6DateTime::TimeZone::BEGIN@6
1119µs38µsDateTime::TimeZone::::BEGIN@26DateTime::TimeZone::BEGIN@26
1117µs7µsDateTime::TimeZone::::BEGIN@13DateTime::TimeZone::BEGIN@13
1117µs54µsDateTime::TimeZone::::BEGIN@15DateTime::TimeZone::BEGIN@15
1116µs30µsDateTime::TimeZone::::BEGIN@24DateTime::TimeZone::BEGIN@24
1116µs30µsDateTime::TimeZone::::BEGIN@25DateTime::TimeZone::BEGIN@25
1116µs32µsDateTime::TimeZone::::BEGIN@18DateTime::TimeZone::BEGIN@18
1116µs31µsDateTime::TimeZone::::BEGIN@23DateTime::TimeZone::BEGIN@23
1116µs31µsDateTime::TimeZone::::BEGIN@22DateTime::TimeZone::BEGIN@22
1116µs31µsDateTime::TimeZone::::BEGIN@21DateTime::TimeZone::BEGIN@21
1114µs4µsDateTime::TimeZone::::BEGIN@14DateTime::TimeZone::BEGIN@14
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_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::::names_in_categoryDateTime::TimeZone::names_in_category
0000s0sDateTime::TimeZone::::names_in_countryDateTime::TimeZone::names_in_country
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
3338µs125µs
# spent 25µs within DateTime::TimeZone::BEGIN@3 which was called # once (25µs+0s) by DateTime::BEGIN@42 at line 3
use 5.006;
# spent 25µs making 1 call to DateTime::TimeZone::BEGIN@3
4
5320µs225µs
# spent 17µs (10+8) within DateTime::TimeZone::BEGIN@5 which was called # once (10µs+8µs) by DateTime::BEGIN@42 at line 5
use strict;
# spent 17µs making 1 call to DateTime::TimeZone::BEGIN@5 # spent 8µs making 1 call to strict::import
6332µs248µs
# spent 29µs (9+20) within DateTime::TimeZone::BEGIN@6 which was called # once (9µs+20µs) by DateTime::BEGIN@42 at line 6
use warnings;
# spent 29µs making 1 call to DateTime::TimeZone::BEGIN@6 # spent 20µs making 1 call to warnings::import
7
81400nsour $VERSION = '1.18';
9
103131µs12.61ms
# spent 2.61ms (2.52+99µs) within DateTime::TimeZone::BEGIN@10 which was called # once (2.52ms+99µs) by DateTime::BEGIN@42 at line 10
use DateTime::TimeZone::Catalog;
# spent 2.61ms making 1 call to DateTime::TimeZone::BEGIN@10
113102µs11.30ms
# spent 1.30ms (237µs+1.06) within DateTime::TimeZone::BEGIN@11 which was called # once (237µs+1.06ms) by DateTime::BEGIN@42 at line 11
use DateTime::TimeZone::Floating;
# spent 1.30ms making 1 call to DateTime::TimeZone::BEGIN@11
123105µs1484µs
# spent 484µs (418+66) within DateTime::TimeZone::BEGIN@12 which was called # once (418µs+66µs) by DateTime::BEGIN@42 at line 12
use DateTime::TimeZone::Local;
# spent 484µs making 1 call to DateTime::TimeZone::BEGIN@12
13323µs17µs
# spent 7µs within DateTime::TimeZone::BEGIN@13 which was called # once (7µs+0s) by DateTime::BEGIN@42 at line 13
use DateTime::TimeZone::OffsetOnly;
# spent 7µs making 1 call to DateTime::TimeZone::BEGIN@13
14324µs14µs
# spent 4µs within DateTime::TimeZone::BEGIN@14 which was called # once (4µs+0s) by DateTime::BEGIN@42 at line 14
use DateTime::TimeZone::UTC;
# spent 4µs making 1 call to DateTime::TimeZone::BEGIN@14
15338µs2101µs
# spent 54µs (7+47) within DateTime::TimeZone::BEGIN@15 which was called # once (7µs+47µs) by DateTime::BEGIN@42 at line 15
use Params::Validate qw( validate validate_pos SCALAR ARRAYREF BOOLEAN );
# spent 54µs making 1 call to DateTime::TimeZone::BEGIN@15 # spent 47µs making 1 call to Exporter::import
16
17335µs2117µs
# spent 64µs (10+54) within DateTime::TimeZone::BEGIN@17 which was called # once (10µs+54µs) by DateTime::BEGIN@42 at line 17
use constant INFINITY => 100**1000;
# spent 64µs making 1 call to DateTime::TimeZone::BEGIN@17 # spent 54µs making 1 call to constant::import
18324µs258µs
# spent 32µs (6+26) within DateTime::TimeZone::BEGIN@18 which was called # once (6µs+26µs) by DateTime::BEGIN@42 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
21323µs255µs
# spent 31µs (6+25) within DateTime::TimeZone::BEGIN@21 which was called # once (6µs+25µs) by DateTime::BEGIN@42 at line 21
use constant UTC_START => 0;
# spent 31µs making 1 call to DateTime::TimeZone::BEGIN@21 # spent 25µs making 1 call to constant::import
22323µs256µs
# spent 31µs (6+25) within DateTime::TimeZone::BEGIN@22 which was called # once (6µs+25µs) by DateTime::BEGIN@42 at line 22
use constant UTC_END => 1;
# spent 31µs making 1 call to DateTime::TimeZone::BEGIN@22 # spent 25µs making 1 call to constant::import
23323µs256µs
# spent 31µs (6+25) within DateTime::TimeZone::BEGIN@23 which was called # once (6µs+25µs) by DateTime::BEGIN@42 at line 23
use constant LOCAL_START => 2;
# spent 31µs making 1 call to DateTime::TimeZone::BEGIN@23 # spent 25µs making 1 call to constant::import
24323µs254µs
# spent 30µs (6+24) within DateTime::TimeZone::BEGIN@24 which was called # once (6µs+24µs) by DateTime::BEGIN@42 at line 24
use constant LOCAL_END => 3;
# spent 30µs making 1 call to DateTime::TimeZone::BEGIN@24 # spent 24µs making 1 call to constant::import
25322µs255µs
# spent 30µs (6+24) within DateTime::TimeZone::BEGIN@25 which was called # once (6µs+24µs) by DateTime::BEGIN@42 at line 25
use constant OFFSET => 4;
# spent 30µs making 1 call to DateTime::TimeZone::BEGIN@25 # spent 24µs making 1 call to constant::import
26331µs268µs
# spent 38µs (9+30) within DateTime::TimeZone::BEGIN@26 which was called # once (9µs+30µs) by DateTime::BEGIN@42 at line 26
use constant IS_DST => 5;
# spent 38µs making 1 call to DateTime::TimeZone::BEGIN@26 # spent 30µs making 1 call to constant::import
2731.96ms289µs
# spent 49µs (10+40) within DateTime::TimeZone::BEGIN@27 which was called # once (10µs+40µs) by DateTime::BEGIN@42 at line 27
use constant SHORT_NAME => 6;
# spent 49µs making 1 call to DateTime::TimeZone::BEGIN@27 # spent 40µs making 1 call to constant::import
28
29111µsmy %SpecialName = map { $_ => 1 }
30 qw( EST MST HST CET EET MET WET EST5EDT CST6CDT MST7MDT PST8PDT );
31
32
# spent 20.4ms (1.54+18.8) within DateTime::TimeZone::new which was called 63 times, avg 323µs/call: # 39 times (877µs+17.9ms) by DateTime::new at line 207 of DateTime.pm, avg 482µs/call # 17 times (485µs+627µs) by DateTime::TimeZone::STORABLE_thaw at line 418, avg 65µs/call # 5 times (135µs+184µs) by DateTime::Format::Strptime::new at line 161 of DateTime/Format/Strptime.pm, avg 64µs/call # once (29µs+49µs) by SimpleDB::Class::SQL::BEGIN@19 at line 45 of DateTime/Infinite.pm # once (15µs+35µs) by SimpleDB::Class::SQL::BEGIN@19 at line 66 of DateTime/Infinite.pm
sub new {
336334µs my $class = shift;
34632.35ms631.75ms my %p = validate(
# spent 1.75ms making 63 calls to Params::Validate::_validate, avg 28µs/call
35 @_,
36 { name => { type => SCALAR } },
37 );
38
3963153µs115.9ms if ( exists $DateTime::TimeZone::Catalog::LINKS{ $p{name} } ) {
# spent 15.9ms making 1 call to utf8::SWASHNEW
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
4663302µs6366µs unless ( $p{name} =~ m,/,
# spent 66µs making 63 calls to DateTime::TimeZone::CORE:match, avg 1µs/call
47 || $SpecialName{ $p{name} } ) {
4863109µs990µs if ( $p{name} eq 'floating' ) {
# spent 90µs making 9 calls to DateTime::TimeZone::Floating::new, avg 10µs/call
49 return DateTime::TimeZone::Floating->new;
50 }
51
525419µs if ( $p{name} eq 'local' ) {
53 return DateTime::TimeZone::Local->TimeZone();
54 }
55
5654309µs44231µs if ( $p{name} eq 'UTC' || $p{name} eq 'Z' ) {
# spent 231µs making 44 calls to DateTime::TimeZone::UTC::new, avg 5µs/call
57 return DateTime::TimeZone::UTC->new;
58 }
59
601052µs10781µs return DateTime::TimeZone::OffsetOnly->new( offset => $p{name} );
# spent 781µs making 10 calls to DateTime::TimeZone::OffsetOnly::new, avg 78µs/call
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 my $e = do {
73 local $@;
74 local $SIG{__DIE__};
75 eval "require $real_class";
76 $@;
77 };
78
79 if ($e) {
80 my $regex = join '.', split /::/, $real_class;
81 $regex .= '\\.pm';
82
83 if ( $e =~ /^Can't locate $regex/i ) {
84 die
85 "The timezone '$p{name}' could not be loaded, or is an invalid name.\n";
86 }
87 else {
88 die $e;
89 }
90 }
91 }
92
93 my $zone = $real_class->instance( name => $p{name}, is_olson => 1 );
94
95 if ( $zone->is_olson() ) {
96 my $object_version
97 = $zone->can('olson_version')
98 ? $zone->olson_version()
99 : 'unknown';
100 my $catalog_version = DateTime::TimeZone::Catalog->OlsonVersion();
101
102 if ( $object_version ne $catalog_version ) {
103 warn
104 "Loaded $real_class, which is from an older version ($object_version) of the Olson database than this installation of DateTime::TimeZone ($catalog_version).\n";
105 }
106 }
107
108 return $zone;
109}
110
111sub _init {
112 my $class = shift;
113 my %p = validate(
114 @_, {
115 name => { type => SCALAR },
116 spans => { type => ARRAYREF },
117 is_olson => { type => BOOLEAN, default => 0 },
118 },
119 );
120
121 my $self = bless {
122 name => $p{name},
123 spans => $p{spans},
124 is_olson => $p{is_olson},
125 }, $class;
126
127 foreach my $k (qw( last_offset last_observance rules max_year )) {
128 my $m = "_$k";
129 $self->{$k} = $self->$m() if $self->can($m);
130 }
131
132 return $self;
133}
134
135sub is_olson { $_[0]->{is_olson} }
136
137sub is_dst_for_datetime {
138 my $self = shift;
139
140 my $span = $self->_span_for_datetime( 'utc', $_[0] );
141
142 return $span->[IS_DST];
143}
144
145sub offset_for_datetime {
146 my $self = shift;
147
148 my $span = $self->_span_for_datetime( 'utc', $_[0] );
149
150 return $span->[OFFSET];
151}
152
153sub offset_for_local_datetime {
154 my $self = shift;
155
156 my $span = $self->_span_for_datetime( 'local', $_[0] );
157
158 return $span->[OFFSET];
159}
160
161sub short_name_for_datetime {
162 my $self = shift;
163
164 my $span = $self->_span_for_datetime( 'utc', $_[0] );
165
166 return $span->[SHORT_NAME];
167}
168
169sub _span_for_datetime {
170 my $self = shift;
171 my $type = shift;
172 my $dt = shift;
173
174 my $method = $type . '_rd_as_seconds';
175
176 my $end = $type eq 'utc' ? UTC_END : LOCAL_END;
177
178 my $span;
179 my $seconds = $dt->$method();
180 if ( $seconds < $self->max_span->[$end] ) {
181 $span = $self->_spans_binary_search( $type, $seconds );
182 }
183 else {
184 my $until_year = $dt->utc_year + 1;
185 $span = $self->_generate_spans_until_match( $until_year, $seconds,
186 $type );
187 }
188
189 # This means someone gave a local time that doesn't exist
190 # (like during a transition into savings time)
191 unless ( defined $span ) {
192 my $err = 'Invalid local time for date';
193 $err .= ' ' . $dt->iso8601 if $type eq 'utc';
194 $err .= " in time zone: " . $self->name;
195 $err .= "\n";
196
197 die $err;
198 }
199
200 return $span;
201}
202
203sub _spans_binary_search {
204 my $self = shift;
205 my ( $type, $seconds ) = @_;
206
207 my ( $start, $end ) = _keys_for_type($type);
208
209 my $min = 0;
210 my $max = scalar @{ $self->{spans} } + 1;
211 my $i = int( $max / 2 );
212
213 # special case for when there are only 2 spans
214 $i++ if $max % 2 && $max != 3;
215
216 $i = 0 if @{ $self->{spans} } == 1;
217
218 while (1) {
219 my $current = $self->{spans}[$i];
220
221 if ( $seconds < $current->[$start] ) {
222 $max = $i;
223 my $c = int( ( $i - $min ) / 2 );
224 $c ||= 1;
225
226 $i -= $c;
227
228 return if $i < $min;
229 }
230 elsif ( $seconds >= $current->[$end] ) {
231 $min = $i;
232 my $c = int( ( $max - $i ) / 2 );
233 $c ||= 1;
234
235 $i += $c;
236
237 return if $i >= $max;
238 }
239 else {
240
241 # Special case for overlapping ranges because of DST and
242 # other weirdness (like Alaska's change when bought from
243 # Russia by the US). Always prefer latest span.
244 if ( $current->[IS_DST] && $type eq 'local' ) {
245
246 # Asia/Dhaka in 2009j goes into DST without any known
247 # end-of-DST date (wtf, Bangladesh).
248 return $current if $current->[UTC_END] == INFINITY;
249
250 my $next = $self->{spans}[ $i + 1 ];
251
252 # Sometimes we will get here and the span we're
253 # looking at is the last that's been generated so far.
254 # We need to try to generate one more or else we run
255 # out.
256 $next ||= $self->_generate_next_span;
257
258 die "No next span in $self->{max_year}" unless defined $next;
259
260 if ( ( !$next->[IS_DST] )
261 && $next->[$start] <= $seconds
262 && $seconds <= $next->[$end] ) {
263 return $next;
264 }
265 }
266
267 return $current;
268 }
269 }
270}
271
272sub _generate_next_span {
273 my $self = shift;
274
275 my $last_idx = $#{ $self->{spans} };
276
277 my $max_span = $self->max_span;
278
279 # Kind of a hack, but AFAIK there are no zones where it takes
280 # _more_ than a year for a _future_ time zone change to occur, so
281 # by looking two years out we can ensure that we will find at
282 # least one more span. Of course, I will no doubt be proved wrong
283 # and this will cause errors.
284 $self->_generate_spans_until_match( $self->{max_year} + 2,
285 $max_span->[UTC_END] + ( 366 * 86400 ), 'utc' );
286
287 return $self->{spans}[ $last_idx + 1 ];
288}
289
290sub _generate_spans_until_match {
291 my $self = shift;
292 my $generate_until_year = shift;
293 my $seconds = shift;
294 my $type = shift;
295
296 my @changes;
297 my @rules = @{ $self->_rules };
298 foreach my $year ( $self->{max_year} .. $generate_until_year ) {
299 for ( my $x = 0; $x < @rules; $x++ ) {
300 my $last_offset_from_std;
301
302 if ( @rules == 2 ) {
303 $last_offset_from_std
304 = $x
305 ? $rules[0]->offset_from_std
306 : $rules[1]->offset_from_std;
307 }
308 elsif ( @rules == 1 ) {
309 $last_offset_from_std = $rules[0]->offset_from_std;
310 }
311 else {
312 my $count = scalar @rules;
313 die
314 "Cannot generate future changes for zone with $count infinite rules\n";
315 }
316
317 my $rule = $rules[$x];
318
319 my $next = $rule->utc_start_datetime_for_year( $year,
320 $self->{last_offset}, $last_offset_from_std );
321
322 # don't bother with changes we've seen already
323 next if $next->utc_rd_as_seconds < $self->max_span->[UTC_END];
324
325 push @changes,
326 DateTime::TimeZone::OlsonDB::Change->new(
327 type => 'rule',
328 utc_start_datetime => $next,
329 local_start_datetime => $next + DateTime::Duration->new(
330 seconds => $self->{last_observance}->total_offset
331 + $rule->offset_from_std
332 ),
333 short_name => sprintf(
334 $self->{last_observance}->format, $rule->letter
335 ),
336 observance => $self->{last_observance},
337 rule => $rule,
338 );
339 }
340 }
341
342 $self->{max_year} = $generate_until_year;
343
344 my @sorted
345 = sort { $a->utc_start_datetime <=> $b->utc_start_datetime } @changes;
346
347 my ( $start, $end ) = _keys_for_type($type);
348
349 my $match;
350 for ( my $x = 1; $x < @sorted; $x++ ) {
351 my $last_total_offset
352 = $x == 1
353 ? $self->max_span->[OFFSET]
354 : $sorted[ $x - 2 ]->total_offset;
355
356 my $span = DateTime::TimeZone::OlsonDB::Change::two_changes_as_span(
357 @sorted[ $x - 1, $x ], $last_total_offset );
358
359 $span = _span_as_array($span);
360
361 push @{ $self->{spans} }, $span;
362
363 $match = $span
364 if $seconds >= $span->[$start] && $seconds < $span->[$end];
365 }
366
367 return $match;
368}
369
370sub max_span { $_[0]->{spans}[-1] }
371
372sub _keys_for_type {
373 $_[0] eq 'utc' ? ( UTC_START, UTC_END ) : ( LOCAL_START, LOCAL_END );
374}
375
376sub _span_as_array {
377 [
378 @{ $_[0] }{
379 qw( utc_start utc_end local_start local_end offset is_dst short_name )
380 }
381 ];
382}
383
384108237µs
# spent 129µs within DateTime::TimeZone::is_floating which was called 108 times, avg 1µs/call: # 55 times (60µs+0s) by DateTime::_handle_offset_modifier at line 275 of DateTime.pm, avg 1µs/call # 18 times (16µs+0s) by DateTime::set_time_zone at line 1951 of DateTime.pm, avg 917ns/call # 17 times (36µs+0s) by DateTime::from_object at line 515 of DateTime.pm, avg 2µs/call # 17 times (16µs+0s) by DateTime::set_time_zone at line 1944 of DateTime.pm, avg 941ns/call # once (1µs+0s) by DateTime::_compare at line 1804 of DateTime.pm
sub is_floating {0}
385
386sub is_utc {0}
387
388sub has_dst_changes {0}
389
3901348µs
# spent 33µs within DateTime::TimeZone::name which was called 13 times, avg 3µs/call: # 11 times (27µs+0s) by DateTime::TimeZone::STORABLE_freeze at line 407, avg 2µs/call # 2 times (5µs+0s) by DateTime::TimeZone::OffsetOnly::STORABLE_freeze at line 50 of DateTime/TimeZone/OffsetOnly.pm, avg 3µs/call
sub name { $_[0]->{name} }
391sub category { ( split /\//, $_[0]->{name}, 2 )[0] }
392
393sub is_valid_name {
394 my $tz;
395 {
396 local $@;
397 local $SIG{__DIE__};
398 $tz = eval { $_[0]->new( name => $_[1] ) };
399 }
400
401 return $tz && $tz->isa('DateTime::TimeZone') ? 1 : 0;
402}
403
404
# spent 93µs (66+27) within DateTime::TimeZone::STORABLE_freeze which was called 11 times, avg 8µs/call: # 11 times (66µs+27µs) by Storable::net_mstore at line 339 of Storable.pm, avg 8µs/call
sub STORABLE_freeze {
405117µs my $self = shift;
406
4071148µs1127µs return $self->name;
# spent 27µs making 11 calls to DateTime::TimeZone::name, avg 2µs/call
408}
409
410
# spent 1.47ms (319µs+1.15) within DateTime::TimeZone::STORABLE_thaw which was called 17 times, avg 86µs/call: # 17 times (319µs+1.15ms) by Storable::mretrieve at line 415 of Storable.pm, avg 86µs/call
sub STORABLE_thaw {
4111710µs my $self = shift;
412177µs my $cloning = shift;
413177µs my $serialized = shift;
414
4151714µs my $class = ref $self || $self;
416
417173µs my $obj;
41817174µs341.15ms if ( $class->isa(__PACKAGE__) ) {
# spent 1.11ms making 17 calls to DateTime::TimeZone::new, avg 65µs/call # spent 39µs making 17 calls to UNIVERSAL::isa, avg 2µs/call
419 $obj = __PACKAGE__->new( name => $serialized );
420 }
421 else {
422 $obj = $class->new( name => $serialized );
423 }
424
4251749µs %$self = %$obj;
426
4271767µs return $self;
428}
429
430#
431# Functions
432#
433
# spent 308µs (265+43) within DateTime::TimeZone::offset_as_seconds which was called 10 times, avg 31µs/call: # 10 times (265µs+43µs) by DateTime::TimeZone::OffsetOnly::new at line 22 of DateTime/TimeZone/OffsetOnly.pm, avg 31µs/call
sub offset_as_seconds {
434 {
435208µs local $@;
4361028µs local $SIG{__DIE__};
4372072µs shift if eval { $_[0]->isa('DateTime::TimeZone') };
438 }
439
440105µs my $offset = shift;
441
442103µs return undef unless defined $offset;
443
444105µs return 0 if $offset eq '0';
445
446104µs my ( $sign, $hours, $minutes, $seconds );
44710110µs2043µs if ( $offset =~ /^([\+\-])?(\d\d?):(\d\d)(?::(\d\d))?$/ ) {
# spent 43µs making 20 calls to DateTime::TimeZone::CORE:match, avg 2µs/call
448 ( $sign, $hours, $minutes, $seconds ) = ( $1, $2, $3, $4 );
449 }
450 elsif ( $offset =~ /^([\+\-])?(\d\d)(\d\d)(\d\d)?$/ ) {
451 ( $sign, $hours, $minutes, $seconds ) = ( $1, $2, $3, $4 );
452 }
453 else {
454 return undef;
455 }
456
457102µs $sign = '+' unless defined $sign;
4581010µs return undef unless $hours >= 0 && $hours <= 99;
459103µs return undef unless $minutes >= 0 && $minutes <= 59;
460 return undef
461103µs unless !defined($seconds) || ( $seconds >= 0 && $seconds <= 59 );
462
4631010µs my $total = $hours * 3600 + $minutes * 60;
464101µs $total += $seconds if $seconds;
465105µs $total *= -1 if $sign eq '-';
466
4671028µs return $total;
468}
469
470
# spent 200µs (182+18) within DateTime::TimeZone::offset_as_string which was called 8 times, avg 25µs/call: # 8 times (182µs+18µs) by DateTime::__ANON__[/usr/local/lib/perl5/site_perl/5.10.1/darwin-2level/DateTime.pm:1015] at line 1015 of DateTime.pm, avg 25µs/call
sub offset_as_string {
471 {
4721610µs local $@;
473825µs local $SIG{__DIE__};
4741674µs818µs shift if eval { $_[0]->isa('DateTime::TimeZone') };
# spent 18µs making 8 calls to UNIVERSAL::isa, avg 2µs/call
475 }
476
47785µs my $offset = shift;
478
47983µs return undef unless defined $offset;
48086µs return undef unless $offset >= -359999 && $offset <= 359999;
481
48288µs my $sign = $offset < 0 ? '-' : '+';
483
48483µs $offset = abs($offset);
485
486811µs my $hours = int( $offset / 3600 );
48785µs $offset %= 3600;
48885µs my $mins = int( $offset / 60 );
48983µs $offset %= 60;
49084µs my $secs = int($offset);
491
492 return (
493830µs $secs
494 ? sprintf( '%s%02d%02d%02d', $sign, $hours, $mins, $secs )
495 : sprintf( '%s%02d%02d', $sign, $hours, $mins )
496 );
497}
498
499# These methods all operate on data contained in the DateTime/TimeZone/Catalog.pm file.
500
501sub all_names {
502 return
503 wantarray
504 ? @DateTime::TimeZone::Catalog::ALL
505 : [@DateTime::TimeZone::Catalog::ALL];
506}
507
508sub categories {
509 return wantarray
510 ? @DateTime::TimeZone::Catalog::CATEGORY_NAMES
511 : [@DateTime::TimeZone::Catalog::CATEGORY_NAMES];
512}
513
514sub links {
515 return
516 wantarray
517 ? %DateTime::TimeZone::Catalog::LINKS
518 : {%DateTime::TimeZone::Catalog::LINKS};
519}
520
521sub names_in_category {
522 shift if $_[0]->isa('DateTime::TimeZone');
523 return unless exists $DateTime::TimeZone::Catalog::CATEGORIES{ $_[0] };
524
525 return wantarray
526 ? @{ $DateTime::TimeZone::Catalog::CATEGORIES{ $_[0] } }
527 : [ $DateTime::TimeZone::Catalog::CATEGORIES{ $_[0] } ];
528}
529
530sub countries {
531 wantarray
532 ? ( sort keys %DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY )
533 : [ sort keys %DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY ];
534}
535
536sub names_in_country {
537 shift if $_[0]->isa('DateTime::TimeZone');
538
539 return
540 unless
541 exists $DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY{ lc $_[0] };
542
543 return
544 wantarray
545 ? @{ $DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY{ lc $_[0] } }
546 : $DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY{ lc $_[0] };
547}
548
54918µs1;
550
551__END__
552
553=head1 NAME
554
555DateTime::TimeZone - Time zone object base class and factory
556
557=head1 SYNOPSIS
558
559 use DateTime;
560 use DateTime::TimeZone;
561
562 my $tz = DateTime::TimeZone->new( name => 'America/Chicago' );
563
564 my $dt = DateTime->now();
565 my $offset = $tz->offset_for_datetime($dt);
566
567=head1 DESCRIPTION
568
569This class is the base class for all time zone objects. A time zone
570is represented internally as a set of observances, each of which
571describes the offset from GMT for a given time period.
572
573Note that without the C<DateTime.pm> module, this module does not do
574much. It's primary interface is through a C<DateTime> object, and
575most users will not need to directly use C<DateTime::TimeZone>
576methods.
577
578=head1 USAGE
579
580This class has the following methods:
581
582=head2 DateTime::TimeZone->new( name => $tz_name )
583
584Given a valid time zone name, this method returns a new time zone
585blessed into the appropriate subclass. Subclasses are named for the
586given time zone, so that the time zone "America/Chicago" is the
587DateTime::TimeZone::America::Chicago class.
588
589If the name given is a "link" name in the Olson database, the object
590created may have a different name. For example, there is a link from
591the old "EST5EDT" name to "America/New_York".
592
593When loading a time zone from the Olson database, the constructor
594checks the version of the loaded class to make sure it matches the
595version of the current DateTime::TimeZone installation. If they do not
596match it will issue a warning. This is useful because time zone names
597may fall out of use, but you may have an old module file installed for
598that time zone.
599
600There are also several special values that can be given as names.
601
602If the "name" parameter is "floating", then a
603C<DateTime::TimeZone::Floating> object is returned. A floating time
604zone does have I<any> offset, and is always the same time. This is
605useful for calendaring applications, which may need to specify that a
606given event happens at the same I<local> time, regardless of where it
607occurs. See RFC 2445 for more details.
608
609If the "name" parameter is "UTC", then a C<DateTime::TimeZone::UTC>
610object is returned.
611
612If the "name" is an offset string, it is converted to a number, and a
613C<DateTime::TimeZone::OffsetOnly> object is returned.
614
615=head3 The "local" time zone
616
617If the "name" parameter is "local", then the module attempts to
618determine the local time zone for the system.
619
620The method for finding the local zone varies by operating system. See
621the appropriate module for details of how we check for the local time
622zone.
623
624=over 4
625
626=item * L<DateTime::TimeZone::Local::Unix>
627
628=item * L<DateTime::TimeZone::Local::Win32>
629
630=item * L<DateTime::TimeZone::Local::VMS>
631
632=back
633
634If a local time zone is not found, then an exception will be thrown.
635
636=head2 $tz->offset_for_datetime( $dt )
637
638Given a C<DateTime> object, this method returns the offset in seconds
639for the given datetime. This takes into account historical time zone
640information, as well as Daylight Saving Time. The offset is
641determined by looking at the object's UTC Rata Die days and seconds.
642
643=head2 $tz->offset_for_local_datetime( $dt )
644
645Given a C<DateTime> object, this method returns the offset in seconds
646for the given datetime. Unlike the previous method, this method uses
647the local time's Rata Die days and seconds. This should only be done
648when the corresponding UTC time is not yet known, because local times
649can be ambiguous due to Daylight Saving Time rules.
650
651=head2 $tz->name
652
653Returns the name of the time zone. If this value is passed to the
654C<new()> method, it is guaranteed to create the same object.
655
656=head2 $tz->short_name_for_datetime( $dt )
657
658Given a C<DateTime> object, this method returns the "short name" for
659the current observance and rule this datetime is in. These are names
660like "EST", "GMT", etc.
661
662It is B<strongly> recommended that you do not rely on these names for
663anything other than display. These names are not official, and many
664of them are simply the invention of the Olson database maintainers.
665Moreover, these names are not unique. For example, there is an "EST"
666at both -0500 and +1000/+1100.
667
668=head2 $tz->is_floating
669
670Returns a boolean indicating whether or not this object represents a
671floating time zone, as defined by RFC 2445.
672
673=head2 $tz->is_utc
674
675Indicates whether or not this object represents the UTC (GMT) time
676zone.
677
678=head2 $tz->has_dst_changes
679
680Indicates whether or not this zone has I<ever> had a change to and
681from DST, either in the past or future.
682
683=head2 $tz->is_olson
684
685Returns true if the time zone is a named time zone from the Olson
686database.
687
688=head2 $tz->category
689
690Returns the part of the time zone name before the first slash. For
691example, the "America/Chicago" time zone would return "America".
692
693=head2 DateTime::TimeZone->is_valid_name($name)
694
695Given a string, this method returns a boolean value indicating whether
696or not the string is a valid time zone name. If you are using
697C<DateTime::TimeZone::Alias>, any aliases you've created will be valid.
698
699=head2 DateTime::TimeZone->all_names
700
701This returns a pre-sorted list of all the time zone names. This list
702does not include link names. In scalar context, it returns an array
703reference, while in list context it returns an array.
704
705=head2 DateTime::TimeZone->categories
706
707This returns a list of all time zone categories. In scalar context,
708it returns an array reference, while in list context it returns an
709array.
710
711=head2 DateTime::TimeZone->links
712
713This returns a hash of all time zone links, where the keys are the
714old, deprecated names, and the values are the new names. In scalar
715context, it returns a hash reference, while in list context it returns
716a hash.
717
718=head2 DateTime::TimeZone->names_in_category( $category )
719
720Given a valid category, this method returns a list of the names in
721that category, without the category portion. So the list for the
722"America" category would include the strings "Chicago",
723"Kentucky/Monticello", and "New_York". In scalar context, it returns
724an array reference, while in list context it returns an array.
725
726The list is returned in order of population by zone, which should mean
727that this order will be the best to use for most UIs.
728
729=head2 DateTime::TimeZone->countries()
730
731Returns a sorted list of all the valid country codes (in lower-case)
732which can be passed to C<names_in_country()>. In scalar context, it
733returns an array reference, while in list context it returns an array.
734
735If you need to convert country codes to names or vice versa you can
736use C<Locale::Country> to do so.
737
738=head2 DateTime::TimeZone->names_in_country( $country_code )
739
740Given a two-letter ISO3166 country code, this method returns a list of
741time zones used in that country. The country code may be of any
742case. In scalar context, it returns an array reference, while in list
743context it returns an array.
744
745=head2 DateTime::TimeZone->offset_as_seconds( $offset )
746
747Given an offset as a string, this returns the number of seconds
748represented by the offset as a positive or negative number. Returns
749C<undef> if $offset is not in the range C<-99:59:59> to C<+99:59:59>.
750
751The offset is expected to match either
752C</^([\+\-])?(\d\d?):(\d\d)(?::(\d\d))?$/> or
753C</^([\+\-])?(\d\d)(\d\d)(\d\d)?$/>. If it doesn't match either of
754these, C<undef> will be returned.
755
756This means that if you want to specify hours as a single digit, then
757each element of the offset must be separated by a colon (:).
758
759=head2 DateTime::TimeZone->offset_as_string( $offset )
760
761Given an offset as a number, this returns the offset as a string.
762Returns C<undef> if $offset is not in the range C<-359999> to C<359999>.
763
764=head2 Storable Hooks
765
766This module provides freeze and thaw hooks for C<Storable> so that the
767huge data structures for Olson time zones are not actually stored in
768the serialized structure.
769
770If you subclass C<DateTime::TimeZone>, you will inherit its hooks,
771which may not work for your module, so please test the interaction of
772your module with Storable.
773
774=head1 SUPPORT
775
776Support for this module is provided via the datetime@perl.org email
777list. See http://datetime.perl.org/?MailingList for details.
778
779Please submit bugs to the CPAN RT system at
780http://rt.cpan.org/NoAuth/ReportBug.html?Queue=datetime%3A%3Atimezone
781or via email at bug-datetime-timezone@rt.cpan.org.
782
783=head1 DONATIONS
784
785If you'd like to thank me for the work I've done on this module,
786please consider making a "donation" to me via PayPal. I spend a lot of
787free time creating free software, and would appreciate any support
788you'd care to offer.
789
790Please note that B<I am not suggesting that you must do this> in order
791for me to continue working on this particular software. I will
792continue to do so, inasmuch as I have in the past, for as long as it
793interests me.
794
795Similarly, a donation made in this way will probably not make me work
796on this software much more, unless I get so many donations that I can
797consider working on free software full time, which seems unlikely at
798best.
799
800To donate, log into PayPal and send money to autarch@urth.org or use
801the button on this page:
802L<http://www.urth.org/~autarch/fs-donation.html>
803
804=head1 AUTHOR
805
806Dave Rolsky <autarch@urth.org>
807
808=head1 CREDITS
809
810This module was inspired by Jesse Vincent's work on
811Date::ICal::Timezone, and written with much help from the
812datetime@perl.org list.
813
814=head1 COPYRIGHT
815
816Copyright (c) 2003-2008 David Rolsky. All rights reserved. This
817program is free software; you can redistribute it and/or modify it
818under the same terms as Perl itself.
819
820The full text of the license can be found in the LICENSE file included
821with this module.
822
823=head1 SEE ALSO
824
825datetime@perl.org mailing list
826
827http://datetime.perl.org/
828
829The tools directory of the DateTime::TimeZone distribution includes
830two scripts that may be of interest to some people. They are
831parse_olson and tests_from_zdump. Please run them with the --help
832flag to see what they can be used for.
833
834=cut
# spent 109µs within DateTime::TimeZone::CORE:match which was called 83 times, avg 1µs/call: # 63 times (66µs+0s) by DateTime::TimeZone::new at line 46 of DateTime/TimeZone.pm, avg 1µs/call # 20 times (43µs+0s) by DateTime::TimeZone::offset_as_seconds at line 447 of DateTime/TimeZone.pm, avg 2µs/call
sub DateTime::TimeZone::CORE:match; # xsub