Get the next, or previous day of week from the current date

Given a date, get the next or previous Monday, or Tuesday etc from the given date. This is useful when working with ical recurring dates.  If the date given is already that day of week, it is returned as the result.

For example to get the following

Every 20th Monday of the year, forever:
DTSTART;TZID=US-Eastern:19970519T090000
RRULE:FREQ=YEARLY;BYDAY=20MO

==> (1997 9:00 AM EDT)May 19
(1998 9:00 AM EDT)May 18
(1999 9:00 AM EDT)May 17

One could get the first Monday of the year, the it is fairly easy to get the 20th !

<?php

global $amr_day_of_week_no;
$amr_day_of_week_no = array (
 'MO' => 1,
 'TU' => 2,
 'WE' => 3,
 'TH' => 4,
 'FR' => 5,
 'SA' => 6,
 'SU' => 0
 );    

 function amr_goto_byday ($dateobj, $byday, $sign)    {
 global $amr_day_of_week_no;    
 $dayofweek = $dateobj->format('w'); /* 0=sunday, 6 = saturday */
 if ($dayofweek == '-1') $dayofweek = get_oldweekdays($dateobj); /* php seems to break around 1760   */
$target     = $amr_day_of_week_no[$byday]; /*  mo=1 ,su=7  */
 $adjustment = $target - $dayofweek;
 if ($sign === '+') {
 if ($adjustment < 0) $adjustment = $adjustment + 7;        
 }
 else if ($adjustment > 0) $adjustment = $adjustment-7;    
 $d2 = new DateTime();
 $d2 = clone ($dateobj);         
 date_modify ($d2,$adjustment.' days');    
 return ($d2);
 }    

 /* --------Test data ------------------------- */
$d[] = new DateTime('2009-12-25');
$d[] = new DateTime('2009-12-28');
$d[] = new DateTime('2009-12-29');
$d[] = new DateTime('2009-12-30');
$d[] = new DateTime('2009-12-31');
$d[] = new DateTime('2010-01-01');
$d[] = new DateTime('2010-01-02');
$d[] = new DateTime('2010-01-03');
$d[] = new DateTime('2010-01-04');
$d[] = new DateTime('2010-01-05');
$d[] = new DateTime('2010-01-06');
$d[] = new DateTime('2010-01-07');
$d[] = new DateTime('2010-01-08');
$d[] = new DateTime('2010-01-09');
$d[] = new DateTime('2010-01-10');
$d[] = new DateTime('2010-01-11');

echo '<table>';    
foreach (array ('TU','WE','TH','FR','SA','SU','MO') as $day) {
 echo '<tr><td> Aiming for '.$day.'</td><td>If not this, then next</td><td>If not this, then prev</td></tr>';                
 foreach ($d as $i => $d2)    {
 $d3 = amr_goto_byday ($d2, $day, '+');
 $d4 = amr_goto_byday ($d2, $day, '-');
 $s = $d2->format('Y m d l');
 echo '<tr><td> '.$s.'</td><td>'.$d3->format('l,Y m d').'</td><td>'.$d4->format('l,Y m d').'</td></tr>';
 }    
}
echo '</table>';   
  
?>