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