[ic] [interchange] Fix month and year adjustment wrapping issue.

Mike Heins mike at heins.net
Mon Jun 5 14:14:16 UTC 2017


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 <
interchange-cvs at icdevgroup.org> wrote:

> commit fb8cd269c691a4d15f154826e4d1aa02eef0540a
> Author: Peter Ajamian <peter at pajamian.dhs.org>
> 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
> interchange-cvs at icdevgroup.org
> http://www.icdevgroup.org/mailman/listinfo/interchange-cvs
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.icdevgroup.org/pipermail/interchange-users/attachments/20170605/7510fd3c/attachment.html>


More information about the interchange-users mailing list