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