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