From 60618d3360ac0a1083074253f1cfcba62425e465 Mon Sep 17 00:00:00 2001 From: Dmitri Iouchtchenko Date: Sun, 29 Jul 2012 13:41:40 -0400 Subject: [PATCH] Fix #61642: modify("+5 weekdays") returns Sunday Adding a non-zero multiple of 5 weekdays to any Friday, Saturday, or Sunday would result in a Sunday instead of the correct date. This patch provides an implementation of do_adjust_special_weekday() which does not suffer from this issue. --- ext/date/lib/tm2unixtime.c | 75 +++++++++++++++++------------------- ext/date/tests/bug61642.phpt | 62 +++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 39 deletions(-) create mode 100644 ext/date/tests/bug61642.phpt diff --git a/ext/date/lib/tm2unixtime.c b/ext/date/lib/tm2unixtime.c index c4830bbef0c7b..9055fee203f54 100644 --- a/ext/date/lib/tm2unixtime.c +++ b/ext/date/lib/tm2unixtime.c @@ -220,55 +220,52 @@ static void do_adjust_relative(timelib_time* time) static void do_adjust_special_weekday(timelib_time* time) { - timelib_sll current_dow, count; + timelib_sll count, dow, rem; count = time->relative.special.amount; + dow = timelib_day_of_week(time->y, time->m, time->d); - current_dow = timelib_day_of_week(time->y, time->m, time->d); - if (count == 0) { - /* skip over saturday and sunday */ - if (current_dow == 6) { - time->d += 2; - } - /* skip over sunday */ - if (current_dow == 0) { - time->d += 1; - } - } else if (count > 0) { - /* skip over saturday and sunday */ - if (current_dow == 5) { - time->d += 2; - } - /* skip over sunday */ - if (current_dow == 6) { + /* Add increments of 5 weekdays as a week, leaving the DOW unchanged. */ + time->d += (count / 5) * 7; + + /* Deal with the remainder. */ + rem = (count % 5); + + if (count > 0) { + if (rem == 0) { + /* Head back to Friday if we stop on the weekend. */ + if (dow == 0) { + time->d -= 2; + } else if (dow == 6) { + time->d -= 1; + } + } else if (dow == 6) { + /* We ended up on Saturday, but there's still work to do, so move + * to Sunday and continue from there. */ time->d += 1; - } - /* add increments of 5 weekdays as a week */ - time->d += (count / 5) * 7; - /* if current DOW plus the remainder > 5, add two days */ - current_dow = timelib_day_of_week(time->y, time->m, time->d); - time->d += (count % 5); - if ((count % 5) + current_dow > 5) { + } else if (dow + rem > 5) { + /* We're on a weekday, but we're going past Friday, so skip right + * over the weekend. */ time->d += 2; } - } else if (count < 0) { - /* skip over sunday and saturday */ - if (current_dow == 1) { - time->d -= 2; - } - /* skip over satruday */ - if (current_dow == 0 ) { + } else { + /* Completely mirror the forward direction. This also covers the 0 + * case, since if we start on the weekend, we want to move forward as + * if we stopped there while going backwards. */ + if (rem == 0) { + if (dow == 6) { + time->d += 2; + } else if (dow == 0) { + time->d += 1; + } + } else if (dow == 0) { time->d -= 1; - } - /* subtract increments of 5 weekdays as a week */ - time->d += (count / 5) * 7; - /* if current DOW minus the remainder < 0, subtract two days */ - current_dow = timelib_day_of_week(time->y, time->m, time->d); - time->d += (count % 5); - if ((count % 5) + current_dow < 1) { + } else if (dow + rem < 1) { time->d -= 2; } } + + time->d += rem; } static void do_adjust_special(timelib_time* time) diff --git a/ext/date/tests/bug61642.phpt b/ext/date/tests/bug61642.phpt new file mode 100644 index 0000000000000..d03a814d88279 --- /dev/null +++ b/ext/date/tests/bug61642.phpt @@ -0,0 +1,62 @@ +--TEST-- +Bug #61642 (modify("+5 weekdays") returns Sunday) +--INI-- +date.timezone=UTC +--FILE-- +format('Y-m-d D'); +} + +echo '### ', implode(' ', $header), "\n\n"; + +foreach ($weekdays as $days) { + $line = array(); + + printf('%+3d ', $days); + + foreach ($dates as $startdate) { + $date = new DateTime($startdate); + $date->modify("{$days} weekdays"); + + $line[] = $date->format('Y-m-d D'); + } + + echo implode(' ', $line), "\n"; +} +?> +--EXPECTF-- +### 2012-03-29 Thu 2012-03-30 Fri 2012-03-31 Sat 2012-04-01 Sun 2012-04-02 Mon 2012-04-03 Tue 2012-04-04 Wed 2012-04-05 Thu + +-11 2012-03-14 Wed 2012-03-15 Thu 2012-03-16 Fri 2012-03-16 Fri 2012-03-16 Fri 2012-03-19 Mon 2012-03-20 Tue 2012-03-21 Wed +-10 2012-03-15 Thu 2012-03-16 Fri 2012-03-19 Mon 2012-03-19 Mon 2012-03-19 Mon 2012-03-20 Tue 2012-03-21 Wed 2012-03-22 Thu + -9 2012-03-16 Fri 2012-03-19 Mon 2012-03-20 Tue 2012-03-20 Tue 2012-03-20 Tue 2012-03-21 Wed 2012-03-22 Thu 2012-03-23 Fri + -8 2012-03-19 Mon 2012-03-20 Tue 2012-03-21 Wed 2012-03-21 Wed 2012-03-21 Wed 2012-03-22 Thu 2012-03-23 Fri 2012-03-26 Mon + -7 2012-03-20 Tue 2012-03-21 Wed 2012-03-22 Thu 2012-03-22 Thu 2012-03-22 Thu 2012-03-23 Fri 2012-03-26 Mon 2012-03-27 Tue + -6 2012-03-21 Wed 2012-03-22 Thu 2012-03-23 Fri 2012-03-23 Fri 2012-03-23 Fri 2012-03-26 Mon 2012-03-27 Tue 2012-03-28 Wed + -5 2012-03-22 Thu 2012-03-23 Fri 2012-03-26 Mon 2012-03-26 Mon 2012-03-26 Mon 2012-03-27 Tue 2012-03-28 Wed 2012-03-29 Thu + -4 2012-03-23 Fri 2012-03-26 Mon 2012-03-27 Tue 2012-03-27 Tue 2012-03-27 Tue 2012-03-28 Wed 2012-03-29 Thu 2012-03-30 Fri + -3 2012-03-26 Mon 2012-03-27 Tue 2012-03-28 Wed 2012-03-28 Wed 2012-03-28 Wed 2012-03-29 Thu 2012-03-30 Fri 2012-04-02 Mon + -2 2012-03-27 Tue 2012-03-28 Wed 2012-03-29 Thu 2012-03-29 Thu 2012-03-29 Thu 2012-03-30 Fri 2012-04-02 Mon 2012-04-03 Tue + -1 2012-03-28 Wed 2012-03-29 Thu 2012-03-30 Fri 2012-03-30 Fri 2012-03-30 Fri 2012-04-02 Mon 2012-04-03 Tue 2012-04-04 Wed + +0 2012-03-29 Thu 2012-03-30 Fri 2012-04-02 Mon 2012-04-02 Mon 2012-04-02 Mon 2012-04-03 Tue 2012-04-04 Wed 2012-04-05 Thu + +1 2012-03-30 Fri 2012-04-02 Mon 2012-04-02 Mon 2012-04-02 Mon 2012-04-03 Tue 2012-04-04 Wed 2012-04-05 Thu 2012-04-06 Fri + +2 2012-04-02 Mon 2012-04-03 Tue 2012-04-03 Tue 2012-04-03 Tue 2012-04-04 Wed 2012-04-05 Thu 2012-04-06 Fri 2012-04-09 Mon + +3 2012-04-03 Tue 2012-04-04 Wed 2012-04-04 Wed 2012-04-04 Wed 2012-04-05 Thu 2012-04-06 Fri 2012-04-09 Mon 2012-04-10 Tue + +4 2012-04-04 Wed 2012-04-05 Thu 2012-04-05 Thu 2012-04-05 Thu 2012-04-06 Fri 2012-04-09 Mon 2012-04-10 Tue 2012-04-11 Wed + +5 2012-04-05 Thu 2012-04-06 Fri 2012-04-06 Fri 2012-04-06 Fri 2012-04-09 Mon 2012-04-10 Tue 2012-04-11 Wed 2012-04-12 Thu + +6 2012-04-06 Fri 2012-04-09 Mon 2012-04-09 Mon 2012-04-09 Mon 2012-04-10 Tue 2012-04-11 Wed 2012-04-12 Thu 2012-04-13 Fri + +7 2012-04-09 Mon 2012-04-10 Tue 2012-04-10 Tue 2012-04-10 Tue 2012-04-11 Wed 2012-04-12 Thu 2012-04-13 Fri 2012-04-16 Mon + +8 2012-04-10 Tue 2012-04-11 Wed 2012-04-11 Wed 2012-04-11 Wed 2012-04-12 Thu 2012-04-13 Fri 2012-04-16 Mon 2012-04-17 Tue + +9 2012-04-11 Wed 2012-04-12 Thu 2012-04-12 Thu 2012-04-12 Thu 2012-04-13 Fri 2012-04-16 Mon 2012-04-17 Tue 2012-04-18 Wed ++10 2012-04-12 Thu 2012-04-13 Fri 2012-04-13 Fri 2012-04-13 Fri 2012-04-16 Mon 2012-04-17 Tue 2012-04-18 Wed 2012-04-19 Thu ++11 2012-04-13 Fri 2012-04-16 Mon 2012-04-16 Mon 2012-04-16 Mon 2012-04-17 Tue 2012-04-18 Wed 2012-04-19 Thu 2012-04-20 Fri