Profile of /usr/local/lib/perl5/site_perl/5.10.1/DateTime/TimeZone.pm

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

File | /usr/local/lib/perl5/site_perl/5.10.1/DateTime/TimeZone.pm
Statements Executed | 1079
Statement Execution Time | 7.18ms

Subroutines — ordered by exclusive time
Calls | P | F | Exclusive Time | Inclusive Time | Subroutine
--- | --- | --- | --- | --- | ---
1 | 1 | 1 | 2.52ms | 2.61ms | DateTime::TimeZone::::BEGIN@10DateTime::TimeZone::BEGIN@10
63 | 5 | 4 | 1.54ms | 20.4ms | DateTime::TimeZone::::newDateTime::TimeZone::new
1 | 1 | 1 | 418µs | 484µs | DateTime::TimeZone::::BEGIN@12DateTime::TimeZone::BEGIN@12
17 | 1 | 1 | 319µs | 1.47ms | DateTime::TimeZone::::STORABLE_thawDateTime::TimeZone::STORABLE_thaw
10 | 1 | 1 | 265µs | 308µs | DateTime::TimeZone::::offset_as_secondsDateTime::TimeZone::offset_as_seconds
1 | 1 | 1 | 237µs | 1.30ms | DateTime::TimeZone::::BEGIN@11DateTime::TimeZone::BEGIN@11
8 | 1 | 1 | 182µs | 200µs | DateTime::TimeZone::::offset_as_stringDateTime::TimeZone::offset_as_string
108 | 5 | 1 | 129µs | 129µs | DateTime::TimeZone::::is_floatingDateTime::TimeZone::is_floating
83 | 2 | 2 | 109µs | 109µs | DateTime::TimeZone::::CORE:matchDateTime::TimeZone::CORE:match (opcode)
11 | 1 | 1 | 66µs | 93µs | DateTime::TimeZone::::STORABLE_freezeDateTime::TimeZone::STORABLE_freeze
13 | 2 | 2 | 33µs | 33µs | DateTime::TimeZone::::nameDateTime::TimeZone::name
1 | 1 | 1 | 25µs | 25µs | DateTime::TimeZone::::BEGIN@3DateTime::TimeZone::BEGIN@3
1 | 1 | 1 | 10µs | 64µs | DateTime::TimeZone::::BEGIN@17DateTime::TimeZone::BEGIN@17
1 | 1 | 1 | 10µs | 17µs | DateTime::TimeZone::::BEGIN@5DateTime::TimeZone::BEGIN@5
1 | 1 | 1 | 10µs | 49µs | DateTime::TimeZone::::BEGIN@27DateTime::TimeZone::BEGIN@27
1 | 1 | 1 | 9µs | 29µs | DateTime::TimeZone::::BEGIN@6DateTime::TimeZone::BEGIN@6
1 | 1 | 1 | 9µs | 38µs | DateTime::TimeZone::::BEGIN@26DateTime::TimeZone::BEGIN@26
1 | 1 | 1 | 7µs | 7µs | DateTime::TimeZone::::BEGIN@13DateTime::TimeZone::BEGIN@13
1 | 1 | 1 | 7µs | 54µs | DateTime::TimeZone::::BEGIN@15DateTime::TimeZone::BEGIN@15
1 | 1 | 1 | 6µs | 30µs | DateTime::TimeZone::::BEGIN@24DateTime::TimeZone::BEGIN@24
1 | 1 | 1 | 6µs | 30µs | DateTime::TimeZone::::BEGIN@25DateTime::TimeZone::BEGIN@25
1 | 1 | 1 | 6µs | 32µs | DateTime::TimeZone::::BEGIN@18DateTime::TimeZone::BEGIN@18
1 | 1 | 1 | 6µs | 31µs | DateTime::TimeZone::::BEGIN@23DateTime::TimeZone::BEGIN@23
1 | 1 | 1 | 6µs | 31µs | DateTime::TimeZone::::BEGIN@22DateTime::TimeZone::BEGIN@22
1 | 1 | 1 | 6µs | 31µs | DateTime::TimeZone::::BEGIN@21DateTime::TimeZone::BEGIN@21
1 | 1 | 1 | 4µs | 4µs | DateTime::TimeZone::::BEGIN@14DateTime::TimeZone::BEGIN@14
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::_generate_next_spanDateTime::TimeZone::_generate_next_span
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::_generate_spans_until_matchDateTime::TimeZone::_generate_spans_until_match
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::_initDateTime::TimeZone::_init
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::_keys_for_typeDateTime::TimeZone::_keys_for_type
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::_span_as_arrayDateTime::TimeZone::_span_as_array
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::_span_for_datetimeDateTime::TimeZone::_span_for_datetime
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::_spans_binary_searchDateTime::TimeZone::_spans_binary_search
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::all_namesDateTime::TimeZone::all_names
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::categoriesDateTime::TimeZone::categories
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::categoryDateTime::TimeZone::category
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::countriesDateTime::TimeZone::countries
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::has_dst_changesDateTime::TimeZone::has_dst_changes
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::is_dst_for_datetimeDateTime::TimeZone::is_dst_for_datetime
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::is_olsonDateTime::TimeZone::is_olson
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::is_utcDateTime::TimeZone::is_utc
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::is_valid_nameDateTime::TimeZone::is_valid_name
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::linksDateTime::TimeZone::links
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::max_spanDateTime::TimeZone::max_span
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::names_in_categoryDateTime::TimeZone::names_in_category
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::names_in_countryDateTime::TimeZone::names_in_country
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::offset_for_datetimeDateTime::TimeZone::offset_for_datetime
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::offset_for_local_datetimeDateTime::TimeZone::offset_for_local_datetime
0 | 0 | 0 | 0s | 0s | DateTime::TimeZone::::short_name_for_datetimeDateTime::TimeZone::short_name_for_datetime

Call graph for these subroutines as a Graphviz dot language file.

Line | State ments | Time on line | Calls | Time in subs | Code
--- | --- | --- | --- | --- | ---
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 use 5.006; # 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 use strict; # 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 use warnings; # 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 use DateTime::TimeZone::Catalog; # 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 use DateTime::TimeZone::Floating; # 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 use DateTime::TimeZone::Local; # 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 use DateTime::TimeZone::OffsetOnly; # 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 use DateTime::TimeZone::UTC; # 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 use Params::Validate qw( validate validate_pos SCALAR ARRAYREF BOOLEAN ); # spent 54µs making 1 call to DateTime::TimeZone::BEGIN@15 # spent 47µs making 1 call to Exporter::import
16 |  |  |  |  |
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 use constant INFINITY => 100**1000; # spent 64µs making 1 call to DateTime::TimeZone::BEGIN@17 # spent 54µs making 1 call to constant::import
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 use constant NEG_INFINITY => -1 * ( 100**1000 ); # spent 32µs making 1 call to DateTime::TimeZone::BEGIN@18 # spent 26µs making 1 call to constant::import
19 |  |  |  |  |
20 |  |  |  |  | # the offsets for each span element
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 use constant UTC_START => 0; # spent 31µs making 1 call to DateTime::TimeZone::BEGIN@21 # spent 25µs making 1 call to constant::import
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 use constant UTC_END => 1; # spent 31µs making 1 call to DateTime::TimeZone::BEGIN@22 # spent 25µs making 1 call to constant::import
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 use constant LOCAL_START => 2; # spent 31µs making 1 call to DateTime::TimeZone::BEGIN@23 # spent 25µs making 1 call to constant::import
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 use constant LOCAL_END => 3; # spent 30µs making 1 call to DateTime::TimeZone::BEGIN@24 # spent 24µs making 1 call to constant::import
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 use constant OFFSET => 4; # 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 use constant IS_DST => 5; # spent 38µs making 1 call to DateTime::TimeZone::BEGIN@26 # spent 30µs making 1 call to constant::import
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 use constant SHORT_NAME => 6; # spent 49µs making 1 call to DateTime::TimeZone::BEGIN@27 # spent 40µs making 1 call to constant::import
28 |  |  |  |  |
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 sub new {
33 | 433 | 2.02ms |  |  | my $class = shift;
34 | 1 | 1.29ms | 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 | 1 | 18µ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 |  |  |  |  | unless ( $p{name} =~ m,/, # spent 66µs making 63 calls to DateTime::TimeZone::CORE:match, avg 1µs/call
47 |  |  |  |  | || $SpecialName{ $p{name} } ) {
48 |  |  |  |  | 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 |  |  |  |  | if ( $p{name} eq 'local' ) {
53 |  |  |  |  | return DateTime::TimeZone::Local->TimeZone();
54 |  |  |  |  | }
55 |  |  |  |  |
56 |  |  |  |  | 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 |  |  |  |  | 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 sub is_floating {0}
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 sub name { $_[0]->{name} }
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 sub STORABLE_freeze {
405 | 22 | 55µs |  |  | my $self = shift;
406 |  |  |  |  |
407 |  |  |  |  | return $self->name; # spent 27µs making 11 calls to DateTime::TimeZone::name, avg 2µs/call
408 |  |  |  |  | }
409 |  |  |  |  |
410 |  |  |  |  | # spent 1.47ms (319µs+1.15) within DateTime::TimeZone::STORABLE_thaw which was called 17 times, avg 86µs/call: # 17 times (319µs+1.15ms) by Storable::mretrieve at line 415 of Storable.pm, avg 86µs/call sub STORABLE_thaw {
411 | 136 | 332µs |  |  | my $self = shift;
412 |  |  |  |  | my $cloning = shift;
413 |  |  |  |  | my $serialized = shift;
414 |  |  |  |  |
415 |  |  |  |  | my $class = ref $self || $self;
416 |  |  |  |  |
417 |  |  |  |  | my $obj;
418 |  |  |  |  | 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 |  |  |  |  | %$self = %$obj;
426 |  |  |  |  |
427 |  |  |  |  | return $self;
428 |  |  |  |  | }
429 |  |  |  |  |
430 |  |  |  |  | #
431 |  |  |  |  | # Functions
432 |  |  |  |  | #
433 |  |  |  |  | # spent 308µs (265+43) within DateTime::TimeZone::offset_as_seconds which was called 10 times, avg 31µs/call: # 10 times (265µs+43µs) by DateTime::TimeZone::OffsetOnly::new at line 22 of DateTime/TimeZone/OffsetOnly.pm, avg 31µs/call sub offset_as_seconds {
434 |  |  |  |  | {
435 | 180 | 296µs |  |  | local $@;
436 |  |  |  |  | local $SIG{__DIE__};
437 |  |  |  |  | shift if eval { $_[0]->isa('DateTime::TimeZone') };
438 |  |  |  |  | }
439 |  |  |  |  |
440 |  |  |  |  | my $offset = shift;
441 |  |  |  |  |
442 |  |  |  |  | return undef unless defined $offset;
443 |  |  |  |  |
444 |  |  |  |  | return 0 if $offset eq '0';
445 |  |  |  |  |
446 |  |  |  |  | my ( $sign, $hours, $minutes, $seconds );
447 |  |  |  |  | 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 |  |  |  |  | $sign = '+' unless defined $sign;
458 |  |  |  |  | return undef unless $hours >= 0 && $hours <= 99;
459 |  |  |  |  | return undef unless $minutes >= 0 && $minutes <= 59;
460 |  |  |  |  | return undef
461 |  |  |  |  | unless !defined($seconds) || ( $seconds >= 0 && $seconds <= 59 );
462 |  |  |  |  |
463 |  |  |  |  | my $total = $hours * 3600 + $minutes * 60;
464 |  |  |  |  | $total += $seconds if $seconds;
465 |  |  |  |  | $total *= -1 if $sign eq '-';
466 |  |  |  |  |
467 |  |  |  |  | return $total;
468 |  |  |  |  | }
469 |  |  |  |  |
470 |  |  |  |  | # spent 200µs (182+18) within DateTime::TimeZone::offset_as_string which was called 8 times, avg 25µs/call: # 8 times (182µs+18µs) by DateTime::__ANON__[/usr/local/lib/perl5/site_perl/5.10.1/darwin-2level/DateTime.pm:1015] at line 1015 of DateTime.pm, avg 25µs/call sub offset_as_string {
471 |  |  |  |  | {
472 | 128 | 191µs |  |  | local $@;
473 |  |  |  |  | local $SIG{__DIE__};
474 |  |  |  |  | shift if eval { $_[0]->isa('DateTime::TimeZone') }; # spent 18µs making 8 calls to UNIVERSAL::isa, avg 2µs/call
475 |  |  |  |  | }
476 |  |  |  |  |
477 |  |  |  |  | my $offset = shift;
478 |  |  |  |  |
479 |  |  |  |  | return undef unless defined $offset;
480 |  |  |  |  | return undef unless $offset >= -359999 && $offset <= 359999;
481 |  |  |  |  |
482 |  |  |  |  | my $sign = $offset < 0 ? '-' : '+';
483 |  |  |  |  |
484 |  |  |  |  | $offset = abs($offset);
485 |  |  |  |  |
486 |  |  |  |  | my $hours = int( $offset / 3600 );
487 |  |  |  |  | $offset %= 3600;
488 |  |  |  |  | my $mins = int( $offset / 60 );
489 |  |  |  |  | $offset %= 60;
490 |  |  |  |  | my $secs = int($offset);
491 |  |  |  |  |
492 |  |  |  |  | return (
493 |  |  |  |  | $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 sub DateTime::TimeZone::CORE:match; # xsub