Mailing List Archive

Re: [interchange] Fix month and year adjustment wrapping issue.
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@icdevgroup.org> wrote:

> commit fb8cd269c691a4d15f154826e4d1aa02eef0540a
> Author: Peter Ajamian <peter@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@icdevgroup.org
> http://www.icdevgroup.org/mailman/listinfo/interchange-cvs
>
Re: [interchange] Fix month and year adjustment wrapping issue. [ In reply to ]
On 06/06/17 02:14, Mike Heins wrote:
> 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.

m still stands for minutes, month requires "mo" at the least, so there
has never been a bc issue with this. This has been in IC since 5.7, I
was just fixing a particular issue with it.


Peter

_______________________________________________
interchange-users mailing list
interchange-users@icdevgroup.org
http://www.icdevgroup.org/mailman/listinfo/interchange-users
Re: [interchange] Fix month and year adjustment wrapping issue. [ In reply to ]
Quoting Peter (peter@pajamian.dhs.org):
> On 06/06/17 02:14, Mike Heins wrote:
> > 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.
>
> m still stands for minutes, month requires "mo" at the least, so there
> has never been a bc issue with this. This has been in IC since 5.7, I
> was just fixing a particular issue with it.

I understand. But because month arithmetic, on the same level that
seconds/minutes/days/weeks arithmetic works well, I didn't support it.
Nowadays I just use Date::Calc to do that stuff, but when your entire
executable size was 39K that wasn't an option.... :)

--
Mike Heins
End Point -- Expert Internet Consulting http://www.endpoint.com/
phone +1.765.253.4194 <mikeh@endpoint.com>

Nature, to be commanded, must be obeyed. -- Francis Bacon

_______________________________________________
interchange-users mailing list
interchange-users@icdevgroup.org
http://www.icdevgroup.org/mailman/listinfo/interchange-users