From 854a56193d32246fcfd67e28ba0fe4caa62cbdfd Mon Sep 17 00:00:00 2001 From: Marcel de Rooy Date: Tue, 9 May 2017 17:01:46 +0200 Subject: [PATCH] Bug 18356: Fix date calculations for yearly frequencies in Serials Content-Type: text/plain; charset=utf-8 The problem as described on BZ 18356 is a combination of an error in GetFictiveIssueNumber and GetNextDate for unit==year. In GetFictiveIssueNumber the year should be decreased by one if you have more units per year and you did not yet reach firstacqui day and month. This affects calculations in GetNextDate with irregularities. In GetNextDate the Add_Delta_YM calculation should be applied only to frequencies based on years per unit. In the case of multiple units per year we calculate the number of days to add. And if we have reached the end of a year cycle, we 'round' up to firstacqui day and month as long as we are close enough. Otherwise we just add the number of calculated days, since we can safely assume that the publish dates have been adjusted manually. Test plan: [1] Verify that both GetNextDate.t as well as GetFictiveIssueNumber.t pass. [2] Look at the prediction pattern for a few frequencies. For example: 1 iss/y, 1 iss/2y, 5 iss/y. Signed-off-by: Marcel de Rooy --- C4/Serials.pm | 50 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/C4/Serials.pm b/C4/Serials.pm index c1316f2..bbb4802 100644 --- a/C4/Serials.pm +++ b/C4/Serials.pm @@ -2270,6 +2270,9 @@ depending on how many rows are in serial table. The issue number calculation is based on subscription frequency, first acquisition date, and $publisheddate. +The routine is used to skip irregularities when calculating the next issue +date (in GetNextDate) or the next issue number (in GetNextSeq). + =cut sub GetFictiveIssueNumber { @@ -2297,6 +2300,10 @@ sub GetFictiveIssueNumber { : ( ($year-$fa_year-1)*12 + (12-$fa_month+$month) ); } elsif($unit eq 'year') { $delta = $year - $fa_year; + if( $frequency->{issuesperunit} > 1 ) { + $delta-- if $month < $fa_month || + ( $month == $fa_month && $day < $fa_day ); + } } if($frequency->{'unitsperissue'} == 1) { $issueno = $delta * $frequency->{'issuesperunit'} + $subscription->{'countissuesperunit'}; @@ -2372,23 +2379,38 @@ sub _get_next_date_month { sub _get_next_date_year { my ($subscription, $freqdata, $year, $month, $day) = @_; - my ($fa_year, $fa_month, $fa_day) = split /-/, $subscription->{firstacquidate}; + my (undef, $fa_month, $fa_day) = split /-/, $subscription->{firstacquidate}; - if ($subscription->{countissuesperunit} + 1 > $freqdata->{issuesperunit}){ - $subscription->{countissuesperunit} = 1; - ($year) = Add_Delta_YM($year,$month,$day, $freqdata->{"unitsperissue"},0); - $month = $fa_month; - my $days_in_month = Days_in_Month($year, $month); - $day = $fa_day <= $days_in_month ? $fa_day : $days_in_month; + my @newissue; # ( yy, mm, dd ) + if( $freqdata->{issuesperunit} == 1 ) { # adding years + @newissue = Add_Delta_YM( + $year, $month, $day, $freqdata->{"unitsperissue"}, 0 ); } else { - # Try to guess the next day in year - my $days_in_year = Days_in_Year($year,12); #Sum the days of all the months of this year - my $delta_days = int(($days_in_year - ($fa_day - 1)) / $freqdata->{issuesperunit}); - ($year,$month,$day) = Add_Delta_Days($year, $month, $day, $delta_days); - $subscription->{countissuesperunit}++; - } + # Add rounded number of days based on frequency. + # We always use the same number of days (calculated with 365.25). + my $delta_days = int( 365.25 / $freqdata->{issuesperunit} ); + @newissue = Add_Delta_Days( $year, $month, $day, $delta_days ); - return ($year, $month, $day); + # Did we finish a cycle of issues within a unit? Correct rounding. + if( $subscription->{countissuesperunit} >= $freqdata->{issuesperunit} ) + { + $subscription->{countissuesperunit} = 1; + my $newyr = $newissue[0]; + $newyr++ if $fa_month < $newissue[1]; + my $days_in_month = Days_in_Month($newyr, $fa_month); + $fa_day = $days_in_month if $fa_day > $days_in_month; + # If newissue is older than the firstacqui based date, and + # difference <= number of issues per unit, we accept + # the firstacqui based date. + # Note: We use <= because of leap years! + $delta_days = Delta_Days( @newissue, $newyr, $fa_month, $fa_day ); + @newissue = ( $newyr, $fa_month, $fa_day ) + if $delta_days > 0 && $delta_days <= $freqdata->{issuesperunit}; + } else { + $subscription->{countissuesperunit}++; + } + } + return @newissue; } =head2 GetNextDate -- 2.1.4