1 package DateTime::TimeZone::OlsonDB::Zone;
6 use DateTime::TimeZone;
7 use DateTime::TimeZone::OlsonDB;
8 use DateTime::TimeZone::OlsonDB::Change;
9 use DateTime::TimeZone::OlsonDB::Observance;
11 use List::Util qw( first );
12 use Params::Validate qw( validate SCALAR ARRAYREF );
17 my %p = validate( @_, { name => { type => SCALAR },
18 observances => { type => ARRAYREF },
23 my $self = { name => $p{name},
24 observances => $p{observances},
29 return bless $self, $class;
32 sub name { $_[0]->{name} }
34 sub expand_observances
41 for ( my $x = 0; $x < @{ $self->{observances} }; $x++ )
43 my %p = %{ $self->{observances}[$x] };
45 my $rules_name = delete $p{rules};
47 my $last_offset_from_std =
48 $self->last_change ? $self->last_change->offset_from_std : 0;
49 my $last_offset_from_utc =
50 $self->last_change ? $self->last_change->offset_from_utc : 0;
53 DateTime::TimeZone::OlsonDB::Observance->new
55 utc_start_datetime => $prev_until,
56 rules => [ $odb->rules_by_name($rules_name) ],
57 last_offset_from_utc => $last_offset_from_utc,
58 last_offset_from_std => $last_offset_from_std,
61 my $rule = $obs->first_rule;
62 my $letter = $rule ? $rule->letter : '';
65 DateTime::TimeZone::OlsonDB::Change->new
66 ( type => 'observance',
67 utc_start_datetime => $obs->utc_start_datetime,
68 local_start_datetime => $obs->local_start_datetime,
69 short_name => sprintf( $obs->format, $letter ),
71 $rule ? ( rule => $rule ) : (),
74 if ($DateTime::TimeZone::OlsonDB::DEBUG)
76 print "Adding observance change ...\n";
78 $change->_debug_output;
81 $self->add_change($change);
85 $obs->expand_from_rules( $self, $max_year );
89 $obs->until( $self->last_change ? $self->last_change->offset_from_std : 0 );
92 if ( $x == $#{ $self->{observances} } )
94 foreach my $rule ( $obs->rules )
96 if ( $rule->is_infinite )
98 $self->add_infinite_rule($rule);
110 if ( defined $change->utc_start_datetime )
112 if ( @{ $self->{changes} }
113 && $self->{changes}[-1]->utc_start_datetime
114 && $self->{changes}[-1]->utc_start_datetime == $change->utc_start_datetime
117 if ( $self->{changes}[-1]->rule && $change->observance )
119 print " Ignoring previous rule change, that starts the same time as current observance change\n\n"
120 if $DateTime::TimeZone::OlsonDB::DEBUG;
122 $self->{changes}[-1] = $change;
127 die "Cannot add two different changes that have the same UTC start datetime!\n";
130 my $last_change = $self->last_change;
132 if ( $last_change->short_name eq $change->short_name
133 && $last_change->total_offset == $change->total_offset
134 && $last_change->is_dst == $change->is_dst
135 && $last_change->observance eq $change->observance
138 my $last_rule = $last_change->rule || '';
139 my $new_rule = $change->rule || '';
141 if ( $last_rule eq $new_rule )
143 print "Skipping identical change\n" if $DateTime::TimeZone::OlsonDB::DEBUG;
149 push @{ $self->{changes} }, $change;
153 if ( $self->{earliest} )
155 die "There can only be one earliest time zone change!";
159 $self->{earliest} = $change;
164 sub add_infinite_rule
166 $_[0]->{infinite_rules}{ $_[1] } = $_[1];
169 sub last_change { return unless @{ $_[0]->{changes} } || $_[0]->{earliest};
170 return ( @{ $_[0]->{changes} } ?
171 $_[0]->{changes}[-1] :
172 $_[0]->{earliest} ); }
174 sub sorted_changes { ( ( defined $_[0]->{earliest} ? $_[0]->{earliest} : () ),
175 sort { $a->utc_start_datetime <=> $b->utc_start_datetime }
176 @{ $_[0]->{changes} } ) }
178 sub infinite_rules { values %{ $_[0]->{infinite_rules} } }