| File | /usr/local/lib/perl5/site_perl/5.10.1/DateTime/TimeZone.pm |
| Statements Executed | 1077 |
| Statement Execution Time | 7.18ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 2.52ms | 2.61ms | DateTime::TimeZone::BEGIN@10 |
| 63 | 5 | 4 | 1.54ms | 20.4ms | DateTime::TimeZone::new |
| 1 | 1 | 1 | 418µs | 484µs | DateTime::TimeZone::BEGIN@12 |
| 17 | 1 | 1 | 319µs | 1.47ms | DateTime::TimeZone::STORABLE_thaw |
| 10 | 1 | 1 | 265µs | 308µs | DateTime::TimeZone::offset_as_seconds |
| 1 | 1 | 1 | 237µs | 1.30ms | DateTime::TimeZone::BEGIN@11 |
| 8 | 1 | 1 | 182µs | 200µs | DateTime::TimeZone::offset_as_string |
| 108 | 5 | 1 | 129µs | 129µs | DateTime::TimeZone::is_floating |
| 83 | 2 | 2 | 109µs | 109µs | DateTime::TimeZone::CORE:match (opcode) |
| 11 | 1 | 1 | 66µs | 93µs | DateTime::TimeZone::STORABLE_freeze |
| 13 | 2 | 2 | 33µs | 33µs | DateTime::TimeZone::name |
| 1 | 1 | 1 | 25µs | 25µs | DateTime::TimeZone::BEGIN@3 |
| 1 | 1 | 1 | 10µs | 64µs | DateTime::TimeZone::BEGIN@17 |
| 1 | 1 | 1 | 10µs | 17µs | DateTime::TimeZone::BEGIN@5 |
| 1 | 1 | 1 | 10µs | 49µs | DateTime::TimeZone::BEGIN@27 |
| 1 | 1 | 1 | 9µs | 29µs | DateTime::TimeZone::BEGIN@6 |
| 1 | 1 | 1 | 9µs | 38µs | DateTime::TimeZone::BEGIN@26 |
| 1 | 1 | 1 | 7µs | 7µs | DateTime::TimeZone::BEGIN@13 |
| 1 | 1 | 1 | 7µs | 54µs | DateTime::TimeZone::BEGIN@15 |
| 1 | 1 | 1 | 6µs | 30µs | DateTime::TimeZone::BEGIN@24 |
| 1 | 1 | 1 | 6µs | 30µs | DateTime::TimeZone::BEGIN@25 |
| 1 | 1 | 1 | 6µs | 32µs | DateTime::TimeZone::BEGIN@18 |
| 1 | 1 | 1 | 6µs | 31µs | DateTime::TimeZone::BEGIN@23 |
| 1 | 1 | 1 | 6µs | 31µs | DateTime::TimeZone::BEGIN@22 |
| 1 | 1 | 1 | 6µs | 31µs | DateTime::TimeZone::BEGIN@21 |
| 1 | 1 | 1 | 4µs | 4µs | DateTime::TimeZone::BEGIN@14 |
| 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_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::names_in_category |
| 0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::names_in_country |
| 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 | |||||
| 3 | 3 | 38µs | 1 | 25µs | # spent 25µs within DateTime::TimeZone::BEGIN@3 which was called
# once (25µs+0s) by DateTime::BEGIN@42 at line 3 # spent 25µs making 1 call to DateTime::TimeZone::BEGIN@3 |
| 4 | |||||
| 5 | 3 | 20µs | 2 | 25µ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 # spent 17µs making 1 call to DateTime::TimeZone::BEGIN@5
# spent 8µs making 1 call to strict::import |
| 6 | 3 | 32µs | 2 | 48µ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 # spent 29µs making 1 call to DateTime::TimeZone::BEGIN@6
# spent 20µs making 1 call to warnings::import |
| 7 | |||||
| 8 | 1 | 400ns | our $VERSION = '1.18'; | ||
| 9 | |||||
| 10 | 3 | 131µs | 1 | 2.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 # spent 2.61ms making 1 call to DateTime::TimeZone::BEGIN@10 |
| 11 | 3 | 102µs | 1 | 1.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 # spent 1.30ms making 1 call to DateTime::TimeZone::BEGIN@11 |
| 12 | 3 | 105µs | 1 | 484µ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 # spent 484µs making 1 call to DateTime::TimeZone::BEGIN@12 |
| 13 | 3 | 23µs | 1 | 7µs | # spent 7µs within DateTime::TimeZone::BEGIN@13 which was called
# once (7µs+0s) by DateTime::BEGIN@42 at line 13 # spent 7µs making 1 call to DateTime::TimeZone::BEGIN@13 |
| 14 | 3 | 24µs | 1 | 4µs | # spent 4µs within DateTime::TimeZone::BEGIN@14 which was called
# once (4µs+0s) by DateTime::BEGIN@42 at line 14 # spent 4µs making 1 call to DateTime::TimeZone::BEGIN@14 |
| 15 | 3 | 38µs | 2 | 101µ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 # spent 54µs making 1 call to DateTime::TimeZone::BEGIN@15
# spent 47µs making 1 call to Exporter::import |
| 16 | |||||
| 17 | 3 | 35µs | 2 | 117µ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 # spent 64µs making 1 call to DateTime::TimeZone::BEGIN@17
# spent 54µs making 1 call to constant::import |
| 18 | 3 | 24µs | 2 | 58µ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 # 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 | ||||
| 21 | 3 | 23µs | 2 | 55µ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 # spent 31µs making 1 call to DateTime::TimeZone::BEGIN@21
# spent 25µs making 1 call to constant::import |
| 22 | 3 | 23µs | 2 | 56µ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 # spent 31µs making 1 call to DateTime::TimeZone::BEGIN@22
# spent 25µs making 1 call to constant::import |
| 23 | 3 | 23µs | 2 | 56µ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 # spent 31µs making 1 call to DateTime::TimeZone::BEGIN@23
# spent 25µs making 1 call to constant::import |
| 24 | 3 | 23µs | 2 | 54µ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 # spent 30µs making 1 call to DateTime::TimeZone::BEGIN@24
# spent 24µs making 1 call to constant::import |
| 25 | 3 | 22µs | 2 | 55µ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 # spent 30µs making 1 call to DateTime::TimeZone::BEGIN@25
# spent 24µs making 1 call to constant::import |
| 26 | 3 | 31µs | 2 | 68µ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 # spent 38µs making 1 call to DateTime::TimeZone::BEGIN@26
# spent 30µs making 1 call to constant::import |
| 27 | 3 | 1.96ms | 2 | 89µ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 # spent 49µs making 1 call to DateTime::TimeZone::BEGIN@27
# spent 40µs making 1 call to constant::import |
| 28 | |||||
| 29 | 1 | 11µs | my %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 | ||||
| 33 | 63 | 34µs | my $class = shift; | ||
| 34 | 63 | 2.35ms | 63 | 1.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 | |||||
| 39 | 63 | 153µs | 1 | 15.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 | |||||
| 46 | 63 | 302µs | 63 | 66µs | unless ( $p{name} =~ m,/, # spent 66µs making 63 calls to DateTime::TimeZone::CORE:match, avg 1µs/call |
| 47 | || $SpecialName{ $p{name} } ) { | ||||
| 48 | 63 | 109µs | 9 | 90µ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 | |||||
| 52 | 54 | 19µs | if ( $p{name} eq 'local' ) { | ||
| 53 | return DateTime::TimeZone::Local->TimeZone(); | ||||
| 54 | } | ||||
| 55 | |||||
| 56 | 54 | 309µs | 44 | 231µ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 | |||||
| 60 | 10 | 52µs | 10 | 781µ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 | |||||
| 111 | sub _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 | |||||
| 135 | sub is_olson { $_[0]->{is_olson} } | ||||
| 136 | |||||
| 137 | sub 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 | |||||
| 145 | sub offset_for_datetime { | ||||
| 146 | my $self = shift; | ||||
| 147 | |||||
| 148 | my $span = $self->_span_for_datetime( 'utc', $_[0] ); | ||||
| 149 | |||||
| 150 | return $span->[OFFSET]; | ||||
| 151 | } | ||||
| 152 | |||||
| 153 | sub 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 | |||||
| 161 | sub 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 | |||||
| 169 | sub _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 | |||||
| 203 | sub _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 | |||||
| 272 | sub _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 | |||||
| 290 | sub _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 | |||||
| 370 | sub max_span { $_[0]->{spans}[-1] } | ||||
| 371 | |||||
| 372 | sub _keys_for_type { | ||||
| 373 | $_[0] eq 'utc' ? ( UTC_START, UTC_END ) : ( LOCAL_START, LOCAL_END ); | ||||
| 374 | } | ||||
| 375 | |||||
| 376 | sub _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 | |||||
| 384 | 108 | 237µ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 | ||
| 385 | |||||
| 386 | sub is_utc {0} | ||||
| 387 | |||||
| 388 | sub has_dst_changes {0} | ||||
| 389 | |||||
| 390 | 13 | 48µ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 | ||
| 391 | sub category { ( split /\//, $_[0]->{name}, 2 )[0] } | ||||
| 392 | |||||
| 393 | sub 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 | ||||
| 405 | 11 | 7µs | my $self = shift; | ||
| 406 | |||||
| 407 | 11 | 48µs | 11 | 27µ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 | ||||
| 411 | 17 | 10µs | my $self = shift; | ||
| 412 | 17 | 7µs | my $cloning = shift; | ||
| 413 | 17 | 7µs | my $serialized = shift; | ||
| 414 | |||||
| 415 | 17 | 14µs | my $class = ref $self || $self; | ||
| 416 | |||||
| 417 | 17 | 3µs | my $obj; | ||
| 418 | 17 | 174µs | 34 | 1.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 | |||||
| 425 | 17 | 49µs | %$self = %$obj; | ||
| 426 | |||||
| 427 | 17 | 67µ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 | ||||
| 434 | { | ||||
| 435 | 20 | 8µs | local $@; | ||
| 436 | 10 | 28µs | local $SIG{__DIE__}; | ||
| 437 | 20 | 72µs | shift if eval { $_[0]->isa('DateTime::TimeZone') }; | ||
| 438 | } | ||||
| 439 | |||||
| 440 | 10 | 5µs | my $offset = shift; | ||
| 441 | |||||
| 442 | 10 | 3µs | return undef unless defined $offset; | ||
| 443 | |||||
| 444 | 10 | 5µs | return 0 if $offset eq '0'; | ||
| 445 | |||||
| 446 | 10 | 4µs | my ( $sign, $hours, $minutes, $seconds ); | ||
| 447 | 10 | 110µs | 20 | 43µ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 | |||||
| 457 | 10 | 2µs | $sign = '+' unless defined $sign; | ||
| 458 | 10 | 10µs | return undef unless $hours >= 0 && $hours <= 99; | ||
| 459 | 10 | 3µs | return undef unless $minutes >= 0 && $minutes <= 59; | ||
| 460 | return undef | ||||
| 461 | 10 | 3µs | unless !defined($seconds) || ( $seconds >= 0 && $seconds <= 59 ); | ||
| 462 | |||||
| 463 | 10 | 10µs | my $total = $hours * 3600 + $minutes * 60; | ||
| 464 | 10 | 1µs | $total += $seconds if $seconds; | ||
| 465 | 10 | 5µs | $total *= -1 if $sign eq '-'; | ||
| 466 | |||||
| 467 | 10 | 28µ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 | ||||
| 471 | { | ||||
| 472 | 16 | 10µs | local $@; | ||
| 473 | 8 | 25µs | local $SIG{__DIE__}; | ||
| 474 | 16 | 74µs | 8 | 18µs | shift if eval { $_[0]->isa('DateTime::TimeZone') }; # spent 18µs making 8 calls to UNIVERSAL::isa, avg 2µs/call |
| 475 | } | ||||
| 476 | |||||
| 477 | 8 | 5µs | my $offset = shift; | ||
| 478 | |||||
| 479 | 8 | 3µs | return undef unless defined $offset; | ||
| 480 | 8 | 6µs | return undef unless $offset >= -359999 && $offset <= 359999; | ||
| 481 | |||||
| 482 | 8 | 8µs | my $sign = $offset < 0 ? '-' : '+'; | ||
| 483 | |||||
| 484 | 8 | 3µs | $offset = abs($offset); | ||
| 485 | |||||
| 486 | 8 | 11µs | my $hours = int( $offset / 3600 ); | ||
| 487 | 8 | 5µs | $offset %= 3600; | ||
| 488 | 8 | 5µs | my $mins = int( $offset / 60 ); | ||
| 489 | 8 | 3µs | $offset %= 60; | ||
| 490 | 8 | 4µs | my $secs = int($offset); | ||
| 491 | |||||
| 492 | return ( | ||||
| 493 | 8 | 30µ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 | |||||
| 501 | sub all_names { | ||||
| 502 | return | ||||
| 503 | wantarray | ||||
| 504 | ? @DateTime::TimeZone::Catalog::ALL | ||||
| 505 | : [@DateTime::TimeZone::Catalog::ALL]; | ||||
| 506 | } | ||||
| 507 | |||||
| 508 | sub categories { | ||||
| 509 | return wantarray | ||||
| 510 | ? @DateTime::TimeZone::Catalog::CATEGORY_NAMES | ||||
| 511 | : [@DateTime::TimeZone::Catalog::CATEGORY_NAMES]; | ||||
| 512 | } | ||||
| 513 | |||||
| 514 | sub links { | ||||
| 515 | return | ||||
| 516 | wantarray | ||||
| 517 | ? %DateTime::TimeZone::Catalog::LINKS | ||||
| 518 | : {%DateTime::TimeZone::Catalog::LINKS}; | ||||
| 519 | } | ||||
| 520 | |||||
| 521 | sub 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 | |||||
| 530 | sub countries { | ||||
| 531 | wantarray | ||||
| 532 | ? ( sort keys %DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY ) | ||||
| 533 | : [ sort keys %DateTime::TimeZone::Catalog::ZONES_BY_COUNTRY ]; | ||||
| 534 | } | ||||
| 535 | |||||
| 536 | sub 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 | |||||
| 549 | 1 | 8µs | 1; | ||
| 550 | |||||
| 551 | __END__ | ||||
| 552 | |||||
| 553 | =head1 NAME | ||||
| 554 | |||||
| 555 | DateTime::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 | |||||
| 569 | This class is the base class for all time zone objects. A time zone | ||||
| 570 | is represented internally as a set of observances, each of which | ||||
| 571 | describes the offset from GMT for a given time period. | ||||
| 572 | |||||
| 573 | Note that without the C<DateTime.pm> module, this module does not do | ||||
| 574 | much. It's primary interface is through a C<DateTime> object, and | ||||
| 575 | most users will not need to directly use C<DateTime::TimeZone> | ||||
| 576 | methods. | ||||
| 577 | |||||
| 578 | =head1 USAGE | ||||
| 579 | |||||
| 580 | This class has the following methods: | ||||
| 581 | |||||
| 582 | =head2 DateTime::TimeZone->new( name => $tz_name ) | ||||
| 583 | |||||
| 584 | Given a valid time zone name, this method returns a new time zone | ||||
| 585 | blessed into the appropriate subclass. Subclasses are named for the | ||||
| 586 | given time zone, so that the time zone "America/Chicago" is the | ||||
| 587 | DateTime::TimeZone::America::Chicago class. | ||||
| 588 | |||||
| 589 | If the name given is a "link" name in the Olson database, the object | ||||
| 590 | created may have a different name. For example, there is a link from | ||||
| 591 | the old "EST5EDT" name to "America/New_York". | ||||
| 592 | |||||
| 593 | When loading a time zone from the Olson database, the constructor | ||||
| 594 | checks the version of the loaded class to make sure it matches the | ||||
| 595 | version of the current DateTime::TimeZone installation. If they do not | ||||
| 596 | match it will issue a warning. This is useful because time zone names | ||||
| 597 | may fall out of use, but you may have an old module file installed for | ||||
| 598 | that time zone. | ||||
| 599 | |||||
| 600 | There are also several special values that can be given as names. | ||||
| 601 | |||||
| 602 | If the "name" parameter is "floating", then a | ||||
| 603 | C<DateTime::TimeZone::Floating> object is returned. A floating time | ||||
| 604 | zone does have I<any> offset, and is always the same time. This is | ||||
| 605 | useful for calendaring applications, which may need to specify that a | ||||
| 606 | given event happens at the same I<local> time, regardless of where it | ||||
| 607 | occurs. See RFC 2445 for more details. | ||||
| 608 | |||||
| 609 | If the "name" parameter is "UTC", then a C<DateTime::TimeZone::UTC> | ||||
| 610 | object is returned. | ||||
| 611 | |||||
| 612 | If the "name" is an offset string, it is converted to a number, and a | ||||
| 613 | C<DateTime::TimeZone::OffsetOnly> object is returned. | ||||
| 614 | |||||
| 615 | =head3 The "local" time zone | ||||
| 616 | |||||
| 617 | If the "name" parameter is "local", then the module attempts to | ||||
| 618 | determine the local time zone for the system. | ||||
| 619 | |||||
| 620 | The method for finding the local zone varies by operating system. See | ||||
| 621 | the appropriate module for details of how we check for the local time | ||||
| 622 | zone. | ||||
| 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 | |||||
| 634 | If a local time zone is not found, then an exception will be thrown. | ||||
| 635 | |||||
| 636 | =head2 $tz->offset_for_datetime( $dt ) | ||||
| 637 | |||||
| 638 | Given a C<DateTime> object, this method returns the offset in seconds | ||||
| 639 | for the given datetime. This takes into account historical time zone | ||||
| 640 | information, as well as Daylight Saving Time. The offset is | ||||
| 641 | determined by looking at the object's UTC Rata Die days and seconds. | ||||
| 642 | |||||
| 643 | =head2 $tz->offset_for_local_datetime( $dt ) | ||||
| 644 | |||||
| 645 | Given a C<DateTime> object, this method returns the offset in seconds | ||||
| 646 | for the given datetime. Unlike the previous method, this method uses | ||||
| 647 | the local time's Rata Die days and seconds. This should only be done | ||||
| 648 | when the corresponding UTC time is not yet known, because local times | ||||
| 649 | can be ambiguous due to Daylight Saving Time rules. | ||||
| 650 | |||||
| 651 | =head2 $tz->name | ||||
| 652 | |||||
| 653 | Returns the name of the time zone. If this value is passed to the | ||||
| 654 | C<new()> method, it is guaranteed to create the same object. | ||||
| 655 | |||||
| 656 | =head2 $tz->short_name_for_datetime( $dt ) | ||||
| 657 | |||||
| 658 | Given a C<DateTime> object, this method returns the "short name" for | ||||
| 659 | the current observance and rule this datetime is in. These are names | ||||
| 660 | like "EST", "GMT", etc. | ||||
| 661 | |||||
| 662 | It is B<strongly> recommended that you do not rely on these names for | ||||
| 663 | anything other than display. These names are not official, and many | ||||
| 664 | of them are simply the invention of the Olson database maintainers. | ||||
| 665 | Moreover, these names are not unique. For example, there is an "EST" | ||||
| 666 | at both -0500 and +1000/+1100. | ||||
| 667 | |||||
| 668 | =head2 $tz->is_floating | ||||
| 669 | |||||
| 670 | Returns a boolean indicating whether or not this object represents a | ||||
| 671 | floating time zone, as defined by RFC 2445. | ||||
| 672 | |||||
| 673 | =head2 $tz->is_utc | ||||
| 674 | |||||
| 675 | Indicates whether or not this object represents the UTC (GMT) time | ||||
| 676 | zone. | ||||
| 677 | |||||
| 678 | =head2 $tz->has_dst_changes | ||||
| 679 | |||||
| 680 | Indicates whether or not this zone has I<ever> had a change to and | ||||
| 681 | from DST, either in the past or future. | ||||
| 682 | |||||
| 683 | =head2 $tz->is_olson | ||||
| 684 | |||||
| 685 | Returns true if the time zone is a named time zone from the Olson | ||||
| 686 | database. | ||||
| 687 | |||||
| 688 | =head2 $tz->category | ||||
| 689 | |||||
| 690 | Returns the part of the time zone name before the first slash. For | ||||
| 691 | example, the "America/Chicago" time zone would return "America". | ||||
| 692 | |||||
| 693 | =head2 DateTime::TimeZone->is_valid_name($name) | ||||
| 694 | |||||
| 695 | Given a string, this method returns a boolean value indicating whether | ||||
| 696 | or not the string is a valid time zone name. If you are using | ||||
| 697 | C<DateTime::TimeZone::Alias>, any aliases you've created will be valid. | ||||
| 698 | |||||
| 699 | =head2 DateTime::TimeZone->all_names | ||||
| 700 | |||||
| 701 | This returns a pre-sorted list of all the time zone names. This list | ||||
| 702 | does not include link names. In scalar context, it returns an array | ||||
| 703 | reference, while in list context it returns an array. | ||||
| 704 | |||||
| 705 | =head2 DateTime::TimeZone->categories | ||||
| 706 | |||||
| 707 | This returns a list of all time zone categories. In scalar context, | ||||
| 708 | it returns an array reference, while in list context it returns an | ||||
| 709 | array. | ||||
| 710 | |||||
| 711 | =head2 DateTime::TimeZone->links | ||||
| 712 | |||||
| 713 | This returns a hash of all time zone links, where the keys are the | ||||
| 714 | old, deprecated names, and the values are the new names. In scalar | ||||
| 715 | context, it returns a hash reference, while in list context it returns | ||||
| 716 | a hash. | ||||
| 717 | |||||
| 718 | =head2 DateTime::TimeZone->names_in_category( $category ) | ||||
| 719 | |||||
| 720 | Given a valid category, this method returns a list of the names in | ||||
| 721 | that 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 | ||||
| 724 | an array reference, while in list context it returns an array. | ||||
| 725 | |||||
| 726 | The list is returned in order of population by zone, which should mean | ||||
| 727 | that this order will be the best to use for most UIs. | ||||
| 728 | |||||
| 729 | =head2 DateTime::TimeZone->countries() | ||||
| 730 | |||||
| 731 | Returns a sorted list of all the valid country codes (in lower-case) | ||||
| 732 | which can be passed to C<names_in_country()>. In scalar context, it | ||||
| 733 | returns an array reference, while in list context it returns an array. | ||||
| 734 | |||||
| 735 | If you need to convert country codes to names or vice versa you can | ||||
| 736 | use C<Locale::Country> to do so. | ||||
| 737 | |||||
| 738 | =head2 DateTime::TimeZone->names_in_country( $country_code ) | ||||
| 739 | |||||
| 740 | Given a two-letter ISO3166 country code, this method returns a list of | ||||
| 741 | time zones used in that country. The country code may be of any | ||||
| 742 | case. In scalar context, it returns an array reference, while in list | ||||
| 743 | context it returns an array. | ||||
| 744 | |||||
| 745 | =head2 DateTime::TimeZone->offset_as_seconds( $offset ) | ||||
| 746 | |||||
| 747 | Given an offset as a string, this returns the number of seconds | ||||
| 748 | represented by the offset as a positive or negative number. Returns | ||||
| 749 | C<undef> if $offset is not in the range C<-99:59:59> to C<+99:59:59>. | ||||
| 750 | |||||
| 751 | The offset is expected to match either | ||||
| 752 | C</^([\+\-])?(\d\d?):(\d\d)(?::(\d\d))?$/> or | ||||
| 753 | C</^([\+\-])?(\d\d)(\d\d)(\d\d)?$/>. If it doesn't match either of | ||||
| 754 | these, C<undef> will be returned. | ||||
| 755 | |||||
| 756 | This means that if you want to specify hours as a single digit, then | ||||
| 757 | each element of the offset must be separated by a colon (:). | ||||
| 758 | |||||
| 759 | =head2 DateTime::TimeZone->offset_as_string( $offset ) | ||||
| 760 | |||||
| 761 | Given an offset as a number, this returns the offset as a string. | ||||
| 762 | Returns C<undef> if $offset is not in the range C<-359999> to C<359999>. | ||||
| 763 | |||||
| 764 | =head2 Storable Hooks | ||||
| 765 | |||||
| 766 | This module provides freeze and thaw hooks for C<Storable> so that the | ||||
| 767 | huge data structures for Olson time zones are not actually stored in | ||||
| 768 | the serialized structure. | ||||
| 769 | |||||
| 770 | If you subclass C<DateTime::TimeZone>, you will inherit its hooks, | ||||
| 771 | which may not work for your module, so please test the interaction of | ||||
| 772 | your module with Storable. | ||||
| 773 | |||||
| 774 | =head1 SUPPORT | ||||
| 775 | |||||
| 776 | Support for this module is provided via the datetime@perl.org email | ||||
| 777 | list. See http://datetime.perl.org/?MailingList for details. | ||||
| 778 | |||||
| 779 | Please submit bugs to the CPAN RT system at | ||||
| 780 | http://rt.cpan.org/NoAuth/ReportBug.html?Queue=datetime%3A%3Atimezone | ||||
| 781 | or via email at bug-datetime-timezone@rt.cpan.org. | ||||
| 782 | |||||
| 783 | =head1 DONATIONS | ||||
| 784 | |||||
| 785 | If you'd like to thank me for the work I've done on this module, | ||||
| 786 | please consider making a "donation" to me via PayPal. I spend a lot of | ||||
| 787 | free time creating free software, and would appreciate any support | ||||
| 788 | you'd care to offer. | ||||
| 789 | |||||
| 790 | Please note that B<I am not suggesting that you must do this> in order | ||||
| 791 | for me to continue working on this particular software. I will | ||||
| 792 | continue to do so, inasmuch as I have in the past, for as long as it | ||||
| 793 | interests me. | ||||
| 794 | |||||
| 795 | Similarly, a donation made in this way will probably not make me work | ||||
| 796 | on this software much more, unless I get so many donations that I can | ||||
| 797 | consider working on free software full time, which seems unlikely at | ||||
| 798 | best. | ||||
| 799 | |||||
| 800 | To donate, log into PayPal and send money to autarch@urth.org or use | ||||
| 801 | the button on this page: | ||||
| 802 | L<http://www.urth.org/~autarch/fs-donation.html> | ||||
| 803 | |||||
| 804 | =head1 AUTHOR | ||||
| 805 | |||||
| 806 | Dave Rolsky <autarch@urth.org> | ||||
| 807 | |||||
| 808 | =head1 CREDITS | ||||
| 809 | |||||
| 810 | This module was inspired by Jesse Vincent's work on | ||||
| 811 | Date::ICal::Timezone, and written with much help from the | ||||
| 812 | datetime@perl.org list. | ||||
| 813 | |||||
| 814 | =head1 COPYRIGHT | ||||
| 815 | |||||
| 816 | Copyright (c) 2003-2008 David Rolsky. All rights reserved. This | ||||
| 817 | program is free software; you can redistribute it and/or modify it | ||||
| 818 | under the same terms as Perl itself. | ||||
| 819 | |||||
| 820 | The full text of the license can be found in the LICENSE file included | ||||
| 821 | with this module. | ||||
| 822 | |||||
| 823 | =head1 SEE ALSO | ||||
| 824 | |||||
| 825 | datetime@perl.org mailing list | ||||
| 826 | |||||
| 827 | http://datetime.perl.org/ | ||||
| 828 | |||||
| 829 | The tools directory of the DateTime::TimeZone distribution includes | ||||
| 830 | two scripts that may be of interest to some people. They are | ||||
| 831 | parse_olson and tests_from_zdump. Please run them with the --help | ||||
| 832 | flag 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 |