Commit:    a6a7787cf25af0cf5b5672b677e20d9d40963137
Author:    Dmitri Iouchtchenko <johnnysp...@gmail.com>         Sun, 29 Jul 2012 
13:41:40 -0400
Committer: Stanislav Malyshev <s...@php.net>      Sun, 5 Aug 2012 19:22:36 -0700
Parents:   9c0a3272e77e86b973120feba190d896272396d1
Branches:  master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=a6a7787cf25af0cf5b5672b677e20d9d40963137

Log:
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.

Bugs:
https://bugs.php.net/61642

Changed paths:
  M  ext/date/lib/tm2unixtime.c
  A  ext/date/tests/bug61642.phpt


Diff:
diff --git a/ext/date/lib/tm2unixtime.c b/ext/date/lib/tm2unixtime.c
index c4830bb..9055fee 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 0000000..d03a814
--- /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--
+<?php
+// ±5 and ±10 (and any non-zero multiple of 5) is broken, but everything else
+// should already work correctly.
+$weekdays = range(-11, 11);
+$dates = array('2012-03-29', '2012-03-30', '2012-03-31', '2012-04-01', 
'2012-04-02', '2012-04-03', '2012-04-04', '2012-04-05');
+
+$header = array();
+
+foreach ($dates as $startdate) {
+       $date = new DateTime($startdate);
+
+       $header[] = $date->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


--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to