From ce6781d3cf8be919b62347ba8bf0c260cd9e07d7 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Thu, 23 Mar 2017 14:18:34 -0400 Subject: [PATCH] LP#1635737 Due date honors variable durations The due date calculation now takes the length of duration components into consideration. For example, "1 day" may be shorter or longer than 24 hours during a time change event, "1 month" may be shorter or longer depending on which month it is currently, etc. Signed-off-by: Bill Erickson --- .../perlmods/lib/OpenILS/Application/AppUtils.pm | 32 ++++++++++++++++++++++ .../lib/OpenILS/Application/Circ/Circulate.pm | 8 +----- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm index a8c6c9ff63..e77bfee678 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm @@ -4,6 +4,7 @@ use OpenILS::Application; use base qw/OpenILS::Application/; use OpenSRF::Utils::Cache; use OpenSRF::Utils::Logger qw/$logger/; +use OpenSRF::Utils qw/:datetime/; use OpenILS::Utils::ModsParser; use OpenSRF::EX qw(:try); use OpenILS::Event; @@ -2384,6 +2385,37 @@ sub verify_migrated_user_password { $e, $user_id, md5_hex($salt . $md5_pass), $pw_type); } +# Adds an interval to a date using PG's interval addition routines. +# This takes the varying length of different intervals into account. +# It knows about time changes, variable length months, and leap years. +# $date : DateTime object +# $interval : interval string +# returns : DateTime object +sub date_plus_interval { + my ($self, $date, $interval, $e) = @_; + + $e ||= OpenILS::Utils::CStoreEditor->new; + + my $pg_date = $e->json_query({ + from => [ + 'pg_catalog.interval_pl_timestamptz', + $interval, $date->strftime('%FT%T%z') + ] + }); + + unless ($pg_date && @$pg_date) { + $logger->error("Invalid date or interval string in ". + "date_plus_interval(date=$date, interval=$interval)"); + return undef; + } + + return DateTime::Format::ISO8601->new->parse_datetime( + cleanse_ISO8601( + $pg_date->[0]->{'pg_catalog.interval_pl_timestamptz'} + ) + ); +} + 1; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm index e12828ccff..24e468199e 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm @@ -2077,16 +2077,10 @@ sub apply_modified_due_date { sub create_due_date { my( $self, $duration, $date_ceiling, $force_date, $start_time ) = @_; - # if there is a raw time component (e.g. from postgres), - # turn it into an interval that interval_to_seconds can parse - $duration =~ s/(\d{2}):(\d{2}):(\d{2})/$1 h $2 m $3 s/o; - # for now, use the server timezone. TODO: use workstation org timezone my $due_date = DateTime->now(time_zone => 'local'); $due_date = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($start_time)) if $start_time; - - # add the circ duration - $due_date->add(seconds => OpenSRF::Utils->interval_to_seconds($duration)); + $due_date = $U->date_plus_interval($due_date, $duration, $self->editor); if($date_ceiling) { my $cdate = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($date_ceiling)); -- 2.11.0