Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions lib/DateTime/TimeZone.pm
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ sub offset_for_datetime {
sub offset_for_local_datetime {
my $self = shift;

my $span = $self->_span_for_datetime( 'local', $_[0] );
my $span = $self->_span_for_datetime( 'local', $_[0], $_[1] );

return $span->[OFFSET];
}
Expand All @@ -210,6 +210,7 @@ sub _span_for_datetime {
my $self = shift;
my $type = shift;
my $dt = shift;
my $ignore_missing_spans = shift;

my $method = $type . '_rd_as_seconds';

Expand All @@ -218,7 +219,7 @@ sub _span_for_datetime {
my $span;
my $seconds = $dt->$method();
if ( $seconds < $self->max_span->[$end] ) {
$span = $self->_spans_binary_search( $type, $seconds );
$span = $self->_spans_binary_search( $type, $seconds, $ignore_missing_spans );
}
else {
my $until_year = $dt->utc_year + 1;
Expand All @@ -244,7 +245,7 @@ sub _span_for_datetime {

sub _spans_binary_search {
my $self = shift;
my ( $type, $seconds ) = @_;
my ( $type, $seconds, $ignore_missing_spans ) = @_;

my ( $start, $end ) = _keys_for_type($type);

Expand Down Expand Up @@ -276,7 +277,15 @@ sub _spans_binary_search {

$i += $c;

return if $i >= $max;
if ($i >= $max) {
# No span found for this time zone? If the user has asked,
# return the previous span so the offset to utc is higher,
# effectively moving the time forward whatever the difference
# in the two spans is (typically 1 hour for DST).
return $self->{spans}[ $i - 1 ] if $ignore_missing_spans;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is $i - 1 good enough (since $i can be > $max, not just == $max) ...


return;
}
}
else {

Expand Down Expand Up @@ -687,14 +696,18 @@ for the given datetime. This takes into account historical time zone
information, as well as Daylight Saving Time. The offset is
determined by looking at the object's UTC Rata Die days and seconds.

=head2 $tz->offset_for_local_datetime( $dt )
=head2 $tz->offset_for_local_datetime( $dt, [ $ignore_missing_spans ] )

Given a C<DateTime> object, this method returns the offset in seconds
for the given datetime. Unlike the previous method, this method uses
the local time's Rata Die days and seconds. This should only be done
when the corresponding UTC time is not yet known, because local times
can be ambiguous due to Daylight Saving Time rules.

If C<$ignore_missing_spans> is true and the local time for C<$dt> does not
Copy link
Member

@autarch autarch Jun 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it makes sense to document this talking about "spans". Note that the docs do not mention this term at all, because it's really just an internal detail.

I think this might be better presented as $fall_forward_on_skipped_time or something like that. Saying "the next span up" seems wrong too. Aren't we going to the previous span? But anyway, I'd say something like this:

If $fall_back_on_skipped_time is true and the local time for C<$dt> does not exist in the time zone (typically because of a DSST change), then we will fall back to nearest previous offset for the local time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, we're going to the previous span but that moves the time forward, so I'd add to the above ...

Note that moving to a previous offset will typically move the time forward, since the new offset from UTC will be larger.

exist in the time zone (due to DST changes for example), the next span
up will be returned.

=head2 $tz->is_dst_for_datetime( $dt )

Given a C<DateTime> object, this method returns true if the DateTime is
Expand Down
44 changes: 44 additions & 0 deletions t/23ignore-missing-spans.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use strict;
use warnings;

use lib 't/lib';
use T::RequireDateTime;

use Test::More;
use Test::Fatal;

use DateTime::TimeZone;
use Try::Tiny;

my $tz = DateTime::TimeZone->new( name => 'America/Denver' );

my $dt = DateTime->new(
year => 2018,
month => 3,
day => 11,
hour => 2,
minute => 0,
second => 0,
time_zone => 'UTC',
);

{
my $error;

try {
my $offset = $tz->offset_for_local_datetime($dt);
}
catch {
$error = $_;
};

like( $error, qr/invalid local time/i, 'got correct error' );
}

{
my $offset = $tz->offset_for_local_datetime( $dt, 1 );
is( $offset, -25200, 'got -7 offset (even though we should be -6)' );
}

done_testing();