Re: [interchange] Fix month and year adjustment wrapping issue.
Mike Heins <[email protected]>
| Newsgroups | gmane.comp.web.interchange.users |
|---|---|
| Message-ID | <CACcURn9Pm-JaMfuafKs7cq9Qw3E5CWL+KVXAD1wizw6gweTc5g@mail.gmail.com> |
Part of this was that I don't believe I ever defined "month" as one of the items in config_to_seconds. It was never intended to be part of an adjustment in the initial conception -- "m" stood for minutes. On Mon, Jun 5, 2017 at 5:17 AM, Peter Ajamian < [email protected]> wrote: > commit fb8cd269c691a4d15f154826e4d1aa02eef0540a > Author: Peter Ajamian <[email protected]> > Date: Mon Jun 5 20:53:00 2017 +1200 > > Fix month and year adjustment wrapping issue. > > Month and year adjustments introduced in 5.7 had a bug where adjusting > the month > to one where the target date doesn't exist caused the day to roll over > into the > following month (ex: May 31st - 1 month became May 1st instead of > April 30th) > and similarily with leapday year adjustments (Feb 29th, 2016 + 1 > year), this was > fixed to adjust to the last day of the correct month instead of > rolling over > into the next month. > > UPGRADE | 13 +++++++++++-- > lib/Vend/Util.pm | 49 ++++++++++++++++++++++++++++++++++++------------- > 2 files changed, 47 insertions(+), 15 deletions(-) > --- > diff --git a/UPGRADE b/UPGRADE > index c5f8cc7..2740d87 100644 > --- a/UPGRADE > +++ b/UPGRADE > @@ -8,8 +8,17 @@ Briefly summarized, here's what you can expect when > upgrading from the > following versions: > > 5.10.x -- A minor bug was fixed in an edge-case usage of the [area] tag > which > - could result in incompatibility if your code relies on the buggy > - behaviour. > + could result in incompatibility if your code relies on the buggy > + behaviour. > + > + -- Month and year adjustments introduced in 5.7 had a bug where > + adjusting the month to one where the target date doesn't exist > caused > + the day to roll over into the following month (ex: May 31st - 1 > month > + became May 1st instead of April 30th) and similarily with > leapday > + year adjustments (Feb 29th, 2016 + 1 year), this was fixed to > adjust > + to the last day of the correct month instead of rolling over > into the > + next month. If your code relies on the old behavior please > update > + it. > > 5.6.x -- Perl 5.8.8 or newer is now generally required to run > Interchange. > See "Known Issues" below. > diff --git a/lib/Vend/Util.pm b/lib/Vend/Util.pm > index 7610e42..866ef3b 100644 > --- a/lib/Vend/Util.pm > +++ b/lib/Vend/Util.pm > @@ -2490,6 +2490,27 @@ sub timecard_read { > # optional. > # > sub adjust_time { > + # We need special adjustments to take into account end of month or > leap year > + # issues in adjusting the month or year. This sub will adjust the > time > + # passed in $time as well as kick back a unixtime of the adjusted > time. > + my $perform_adjust = sub { > + my ($time, $adjust) = @_; > + # Do an adjustment based on year and month first to check for > issues > + # with leap year and end of month variances. We set isdst to -1 to > + # avoid variances due to DST time change. > + my @timecheck = @$time; > + $timecheck[5] += $adjust->[5]; > + $timecheck[4] += $adjust->[4]; > + $timecheck[8] = -1; > + my @adjusted = localtime(POSIX::mktime(@timecheck)); > + # If the day is off we need to add an additional adjustment for it. > + $adjust->[3] -= $adjusted[3] if $adjusted[3] < $timecheck[3]; > + $time->[$_] += $adjust->[$_] for (0..5); > + my $unixtime = POSIX::mktime(@$time); > + @$time = localtime($unixtime); > + return $unixtime; > + }; > + > my ($adjust, $time, $compensate_dst) = @_; > $time ||= time; > > @@ -2511,6 +2532,7 @@ sub adjust_time { > # or leave the time the same). > > my @times = localtime($time); > + my @adjust = (0)x6; > my $sign = 1; > > foreach my $amount ($adjust =~ /([+-]?\s*[\d\.]+\s*[a-z]*)/ig) { > @@ -2527,12 +2549,12 @@ sub adjust_time { > $amount *= 7; > } > > - if ($unit =~ /^s/) { $times[0] += $amount } > - elsif ($unit =~ /^mo/) { $times[4] += $amount } # has to come > before min > - elsif ($unit =~ /^m/) { $times[1] += $amount } > - elsif ($unit =~ /^h/) { $times[2] += $amount } > - elsif ($unit =~ /^d/) { $times[3] += $amount } > - elsif ($unit =~ /^y/) { $times[5] += $amount } > + if ($unit =~ /^s/) { $adjust[0] += $amount } > + elsif ($unit =~ /^mo/) { $adjust[4] += $amount } # has to come > before min > + elsif ($unit =~ /^m/) { $adjust[1] += $amount } > + elsif ($unit =~ /^h/) { $adjust[2] += $amount } > + elsif ($unit =~ /^d/) { $adjust[3] += $amount } > + elsif ($unit =~ /^y/) { $adjust[5] += $amount } > > else { > ::logError("adjust_time(): bad unit: $unit"); > @@ -2546,26 +2568,27 @@ sub adjust_time { > my @multip = (0, 60, 60, 24, 0, 12); > my $monfrac = 0; > foreach my $i (reverse 0..5) { > - if ($times[$i] =~ /\./) { > + if ($adjust[$i] =~ /\./) { > if ($multip[$i]) { > - $times[$i-1] += ($times[$i] - int $times[$i]) * > $multip[$i]; > + $adjust[$i-1] += ($adjust[$i] - int $adjust[$i]) * > $multip[$i]; > } > > elsif ($i == 4) { > # Fractions of a month need some really extra special > handling. > - $monfrac = $times[$i] - int $times[$i]; > + $monfrac = $adjust[$i] - int $adjust[$i]; > } > > - $times[$i] = int $times[$i] > + $adjust[$i] = int $adjust[$i]; > } > } > > - $time = POSIX::mktime(@times); > + $time = $perform_adjust->(\@times, \@adjust); > > # This is how we handle a fraction of a month: > if ($monfrac) { > - $times[4] += $monfrac > 0 ? 1 : -1; > - my $timediff = POSIX::mktime(@times); > + @adjust = (0)x6; > + $adjust[4] = $monfrac > 0 ? 1 : -1; > + my $timediff = $perform_adjust->(\@times, \@adjust); > $timediff = int(abs($timediff - $time) * $monfrac); > $time += $timediff; > } > > _______________________________________________ > interchange-cvs mailing list > [email protected] > http://www.icdevgroup.org/mailman/listinfo/interchange-cvs > _______________________________________________ interchange-users mailing list [email protected] http://www.icdevgroup.org/mailman/listinfo/interchange-users