Bug 23079: Handle invalid timezones when adding/subtracting durations
authorJonathan Druart <jonathan.druart@bugs.koha-community.org>
Sun, 23 Jun 2019 01:40:04 +0000 (20:40 -0500)
committerMartin Renvoize <martin.renvoize@ptfs-europe.com>
Fri, 6 Sep 2019 12:17:47 +0000 (13:17 +0100)
On Nov 3rd 2019, Brazil will skip from 00:00 to 1:00 (http://www.currenttimeonline.com/dst/dst.do?tz=America/Sao_Paulo), DateTime consider it as an invalid date.
It is a problem when we are playing with dates without the time part (always 00:00).
When we instantiate a DateTime (from dt_from_string) we are already handling this issue, and use the floating timezone (since bug 12669).

The problem remains when we generate a DateTime then add or subtract a duration, which will result in an invalid date:

DateTime->new(year => 2019, month => 12, day => 3, time_zone => 'America/Sao_Paulo')->subtract(days => 30);

=> Nov 3rd 2019, kaboom.

We should replace all the problematic occurrences of dt_from_string->subtract (or ->add)
with dt_from_string(undef, undef, 'floating'), to use the floating timezone and avoid the error.

Actually there are not many of them, I have found only 3 that could
produce real problems.

The other occurrences are:
- in tests => Not a big deal (for now)
- called on a datetime, so it will explode if called at midnight
00:00:00 (and nobody should work at that time).

Test plan:
0/ Define the timezone to 'America/Sao_Paulo' (in your koha-conf.xml file), restart_all
1/ Set a patron's expiry date to Dec 3rd 2019, and
NotifyBorrowerDeparture to 30 (default value)
2/ See the checkouts page for this user
=> Without this patch you get "Invalid local time for date in time zone:
America/Sao_Paulo"
=> With this patch apply the page displays correctly

QA will review the 2 other occurrences.

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>

Koha/Patron.pm
acqui/duplicate_orders.pl
acqui/histsearch.pl

index ab49821..6f31ec4 100644 (file)
@@ -657,7 +657,7 @@ sub is_going_to_expire {
     return 0 unless $delay;
     return 0 unless $self->dateexpiry;
     return 0 if $self->dateexpiry =~ '^9999';
-    return 1 if dt_from_string( $self->dateexpiry )->subtract( days => $delay ) < dt_from_string->truncate( to => 'day' );
+    return 1 if dt_from_string( $self->dateexpiry, undef, 'floating' )->subtract( days => $delay ) < dt_from_string(undef, undef, 'floating')->truncate( to => 'day' );
     return 0;
 }
 
index 549c8b4..a4a02fc 100755 (executable)
@@ -74,7 +74,7 @@ my $to_placed_on =
 
 unless ( $input->param('from') ) {
     # Fill the form with year-1
-    $from_placed_on->subtract( years => 1 );
+    $from_placed_on->set_time_zone('floating')->subtract( years => 1 );
 }
 $filters->{from_placed_on} =
   output_pref( { dt => $from_placed_on, dateformat => 'iso', dateonly => 1 } ),
index f5dca49..93bca34 100755 (executable)
@@ -94,7 +94,7 @@ my $from_placed_on = eval { dt_from_string( scalar $input->param('from') ) } ||
 my $to_placed_on   = eval { dt_from_string( scalar $input->param('to')   ) } || dt_from_string;
 unless ( $input->param('from') ) {
     # Fill the form with year-1
-    $from_placed_on->subtract( years => 1 );
+    $from_placed_on->set_time_zone('floating')->subtract( years => 1 );
 }
 $filters->{from_placed_on} = output_pref( { dt => $from_placed_on, dateformat => 'iso', dateonly => 1 } ),
 $filters->{to_placed_on} = output_pref( { dt => $to_placed_on, dateformat => 'iso', dateonly => 1 } ),