File Coverage

blib/lib/DateTime/TimeZone/OlsonDB/Zone.pm
Criterion Covered Total %
statement 24 95 25.2
branch 0 42 0.0
condition 0 22 0.0
subroutine 8 17 47.0
pod 0 9 0.0
total 32 185 17.3


line stmt bran cond sub pod time code
1             package DateTime::TimeZone::OlsonDB::Zone;
2              
3 13     13   133 use strict;
  13         53  
  13         549  
4 13     13   75 use warnings;
  13         31  
  13         658  
5 13     13   73 use namespace::autoclean;
  13         27  
  13         90  
6              
7             our $VERSION = '2.67';
8              
9 13     13   1266 use DateTime::TimeZone;
  13         30  
  13         352  
10 13     13   65 use DateTime::TimeZone::OlsonDB;
  13         27  
  13         338  
11 13     13   68 use DateTime::TimeZone::OlsonDB::Change;
  13         23  
  13         331  
12 13     13   8414 use DateTime::TimeZone::OlsonDB::Observance;
  13         49  
  13         722  
13 13     13   235 use List::Util qw( first max );
  13         43  
  13         17997  
14              
15             sub new {
16 0     0 0   my $class = shift;
17 0           my %p = @_;
18              
19             my $self = {
20             name => $p{name},
21             observances => $p{observances},
22 0           changes => [],
23             infinite_rules => {},
24             };
25              
26 0           return bless $self, $class;
27             }
28              
29 0     0 0   sub name { $_[0]->{name} }
30              
31             sub last_rules_year {
32 0     0 0   my $self = shift;
33 0           my $odb = shift;
34              
35 0           my $last_rule = $self->{observances}[-1]{rules};
36              
37 0 0         return unless $last_rule;
38              
39 0           my @rules = $odb->rules_by_name($last_rule);
40              
41 0           return $rules[-1]->min_year();
42             }
43              
44             sub expand_observances {
45 0     0 0   my $self = shift;
46 0           my $odb = shift;
47 0           my $max_year = shift;
48              
49 0           my $prev_until;
50             ## no critic (ControlStructures::ProhibitCStyleForLoops)
51 0           for ( my $x = 0; $x < @{ $self->{observances} }; $x++ ) {
  0            
52 0           my %p = %{ $self->{observances}[$x] };
  0            
53              
54 0           my $rules_name = delete $p{rules};
55              
56 0 0         my $last_offset_from_std
57             = $self->last_change ? $self->last_change->offset_from_std : 0;
58 0 0         my $last_offset_from_utc
59             = $self->last_change ? $self->last_change->offset_from_utc : 0;
60              
61 0           my $obs = DateTime::TimeZone::OlsonDB::Observance->new(
62             %p,
63             utc_start_datetime => $prev_until,
64             rules => [ $odb->rules_by_name($rules_name) ],
65             last_offset_from_utc => $last_offset_from_utc,
66             last_offset_from_std => $last_offset_from_std,
67             );
68              
69 0           my $rule = $obs->first_rule;
70 0 0         my $letter = $rule ? $rule->letter : q{};
71              
72 0 0         my $change = DateTime::TimeZone::OlsonDB::Change->new(
73             type => 'observance',
74             utc_start_datetime => $obs->utc_start_datetime,
75             local_start_datetime => $obs->local_start_datetime,
76             short_name => $obs->formatted_short_name( $letter, $rule ),
77             observance => $obs,
78             $rule ? ( rule => $rule ) : (),
79             );
80              
81 0 0         if ($DateTime::TimeZone::OlsonDB::DEBUG) {
82             ## no critic (InputOutput::RequireCheckedSyscalls)
83 0           print "Adding observance change ...\n";
84              
85 0           $change->_debug_output;
86             }
87              
88 0           $self->add_change($change);
89              
90 0 0         if ( $obs->rules ) {
91 0           $obs->expand_from_rules( $self, $max_year );
92             }
93              
94 0 0         $prev_until = $obs->until(
95             $self->last_change ? $self->last_change->offset_from_std : 0 );
96              
97             # last observance
98 0 0         if ( $x == $#{ $self->{observances} } ) {
  0            
99 0           foreach my $rule ( $obs->rules ) {
100 0 0         if ( $rule->is_infinite ) {
101 0           $self->add_infinite_rule($rule);
102             }
103             }
104             }
105             }
106             }
107              
108             sub add_change {
109 0     0 0   my $self = shift;
110 0           my $change = shift;
111              
112 0 0         if ( defined $change->utc_start_datetime ) {
113 0 0 0       if ( @{ $self->{changes} }
  0   0        
114             && $self->{changes}[-1]->utc_start_datetime
115             && $self->{changes}[-1]->utc_start_datetime
116             == $change->utc_start_datetime ) {
117 0 0 0       if ( $self->{changes}[-1]->rule && $change->observance ) {
118             ## no critic (InputOutput::RequireCheckedSyscalls)
119 0 0         print
120             " Ignoring previous rule change, that starts the same time as current observance change\n\n"
121             if $DateTime::TimeZone::OlsonDB::DEBUG;
122              
123 0           $self->{changes}[-1] = $change;
124              
125 0           return;
126             }
127              
128             die
129 0           "Cannot add two different changes that have the same UTC start datetime!\n";
130             }
131              
132 0           my $last_change = $self->last_change;
133              
134 0 0 0       if ( $last_change->short_name eq $change->short_name
      0        
135             && $last_change->total_offset == $change->total_offset
136             && $last_change->is_dst == $change->is_dst ) {
137 0   0       my $last_rule = $last_change->rule || q{};
138 0   0       my $new_rule = $change->rule || q{};
139              
140             ## no critic (InputOutput::RequireCheckedSyscalls)
141 0 0         print "Skipping identical change\n"
142             if $DateTime::TimeZone::OlsonDB::DEBUG;
143 0           return;
144             }
145              
146 0           push @{ $self->{changes} }, $change;
  0            
147             }
148             else {
149 0 0         if ( $self->{earliest} ) {
150 0           die 'There can only be one earliest time zone change!';
151             }
152             else {
153 0           $self->{earliest} = $change;
154             }
155             }
156             }
157              
158             sub add_infinite_rule {
159 0     0 0   $_[0]->{infinite_rules}{ $_[1] } = $_[1];
160             }
161              
162             sub last_change {
163 0 0 0 0 0   return unless @{ $_[0]->{changes} } || $_[0]->{earliest};
  0            
164             return (
165 0           @{ $_[0]->{changes} }
166             ? $_[0]->{changes}[-1]
167             : $_[0]->{earliest}
168 0 0         );
169             }
170              
171             sub sorted_changes {
172             (
173             ( defined $_[0]->{earliest} ? $_[0]->{earliest} : () ),
174 0           sort { $a->utc_start_datetime <=> $b->utc_start_datetime }
175 0 0   0 0   @{ $_[0]->{changes} }
  0            
176             );
177             }
178              
179             sub infinite_rules {
180 0 0         my @v = sort { $a->min_year <=> $b->min_year || $a->month cmp $b->month }
181 0     0 0   values %{ $_[0]->{infinite_rules} };
  0            
182 0           return @v;
183             }
184              
185             1;