{
my $err = 'Invalid local time for date';
$err .= ' ' . $dt->iso8601 if $type eq 'utc';
$err .= " in time zone: " . $self->name;
$err .= "\n";
die $err;
}
return $span;
}
sub _spans_binary_search
{
my $self = shift;
my ( $type, $seconds ) = @_;
my ( $start, $end ) = _keys_for_type($type);
my $min = 0;
my $max = scalar @{ $self->{spans} } + 1;
my $i = int( $max / 2 );
# special case for when there are only 2 spans
$i++ if $max % 2 && $max != 3;
$i = 0 if @{ $self->{spans} } == 1;
while (1)
{
my $current = $self->{spans}[$i];
if ( $seconds < $current->[$start] )
{
$max = $i;
my $c = int( ( $i - $min ) / 2 );
$c ||= 1;
$i -= $c;
return if $i < $min;
}
elsif ( $seconds >= $current->[$end] )
{
$min = $i;
my $c = int( ( $max - $i ) / 2 );
$c ||= 1;
$i += $c;
return if $i >= $max;
}
else
{
# Special case for overlapping ranges because of DST and
# other weirdness (like Alaska's change when bought from
# Russia by the US). Always prefer latest span.
if ( $current->[IS_DST] && $type eq 'local' )
{
my $next = $self->{spans}[$i + 1];
# Sometimes we will get here and the span we're
# looking at is the last that's been generated so far.
# We need to try to generate one more or else we run
# out.
$next ||= $self->_generate_next_span;
die "No next span in $self->{max_year}" unless defined $next;
if ( ( ! $next->[IS_DST] )
&& $next->[$start] <= $seconds
&& $seconds <= $next->[$end]
)
{
return $next;
}
}
return $current;
}
}
}
sub _generate_next_span
{
my $self = shift;
my $last_idx = $#{ $self->{spans} };
my $max_span = $self->max_span;
# Kind of a hack, but AFAIK there are no zones where it takes
# _more_ than a year for a _future_ time zone change to occur, so
# by looking two years out we can ensure that we will find at
# least one more span. Of course, I will no doubt be proved wrong
# and this will cause errors.
$self->_generate_spans_until_match
( $self->{max_year} + 2, $max_span->[UTC_END] + ( 366 * 86400 ), 'utc' );
return $self->{spans}[ $last_idx + 1 ];
}
=3= |