/**
  * Move the internal "pointer" to the next recurrence in the set
  * and return it.
  * @return qCal_DateTime The next date/time recurrence in the set
  * @access public
  */
 public function next()
 {
     // make a copy of the start date/time to work with
     $startDate = $this->current->getDate();
     $startTime = $this->current->getTime();
     $month = $startDate->getMonth();
     $year = $startDate->getYear();
     // if there is no "next" recurrence in the timeArray, we need to
     // regenerate it with new times for the next day in the recurrence list
     if (!($current = next($this->timeArray))) {
         // if there is no "next" day in the monthArray, we need to regenerate
         // the monthArray. It is possible that it hasn't been generated in
         // the first place, so we need to determine if it should be
         // regenerated for the current year, or for the next year interval
         if (!($currentDay = next($this->monthArray))) {
             // determine if we need to generate the monthArray with the current
             // year or with the next year interval
             if (!empty($this->monthArray)) {
                 $nextmonth = $month + $this->getInterval();
                 if ($nextmonth > 12) {
                     $nextmonth = $nextmonth - 12;
                     $year++;
                 }
                 $month = $nextmonth;
             }
             // $this->currentDay will be assigned when the monthArray is created
             // we will now need to regenerate the monthArray with the data above
             $this->regenerateMonthArray = true;
         } else {
             $this->currentDay = $currentDay;
         }
         // regenerate the timeArray once the yearArray is regenerated
         $this->regenerateTimeArray = true;
     } else {
         $this->current = $current;
     }
     // create a multi-dimensional array of dates that will be looped over
     // when the object is looped over. Each date will have one or more
     // times which will result in even more recurrences. We do not build
     // the time recurrences for the entire month because it takes too long.
     // @todo If this is not the first time we are building this array, we
     // need to skip ahead by $this->interval months.
     if ($this->regenerateMonthArray) {
         $monthArray = array();
         // this date object is used to find out how many days are in the current month
         $ml = new qCal_Date($year, $month, 1);
         for ($d = 1; $d <= $ml->getNumDaysInMonth(); $d++) {
             $day = new qCal_Date($year, $month, $d);
             if ($this->checkDateAgainstRules($day)) {
                 // if this day is equal to or greater than the start
                 // date, add it to the yearArray
                 if ($day->getUnixTimestamp() >= $startDate->getUnixTimestamp()) {
                     $monthArray[$day->format("Ymd")] = $day;
                 }
             }
         }
         $this->monthArray = $monthArray;
         $this->currentDay = current($this->monthArray);
         // now that we have cached the monthArray, we don't need to
         // regenerate it until we have gotten to the next year increment
         $this->regenerateMonthArray = false;
     }
     // if the time recurrences for the current date haven't been created
     // yet, then create them and assign the "current" value to the first
     // time recurrence in the set. If the time recurrences are already
     // available, move the "current" position ahead one recurrence.
     if ($this->regenerateTimeArray) {
         $this->timeArray = $this->findTimeRecurrences($this->currentDay);
         // now that we have cached the timeArray, we don't need to
         // regenerate it until we have gotten to the next day
         $this->regenerateTimeArray = false;
         $this->current = current($this->timeArray);
     }
     // now find the "next" recurrence, advance the "current" date and
     // return the recurrence
     // @TODO When I come back to this tomorrow, I need to take what I have
     // right now, which is an array of dates that are within the recurrence
     // rule set, along with an array of times on each day, and I need to
     // make this object capable of properly looping over these things.
     return $this->current;
     /**
      * This is the old code. It was used to create an array containing twelve arrays (one
      * for each month) of 28-31 days (one for each day of the month)
     if (empty($this->yearArray) || $regenerateYearArray) {
     	$yearArray = array();
     	for($m = 1; $m <= 12; $m++) {
     		$month = new qCal_Date($startDate->getYear(), $m, 1);
     		$monthArray = array();
     		for ($d = 1; $d <= $month->getNumDaysInMonth(); $d++) {
     			$day = new qCal_Date($startDate->getYear(), $m, $d);
     			$monthArray[$d] = $day;
     		}
     		$yearArray[$m] = $monthArray;
     	}
     	$this->yearArray = $yearArray;
     }
     */
 }
 /**
  * The date object has many getters which allow for you to determine things like day of the week,
  * day of the year, etc. The following tests those getters.
  */
 public function testGetters()
 {
     $date = new qCal_Date(2009, 4, 23);
     /**
      * Month
      */
     $this->assertEqual($date->getMonth(), 4);
     $this->assertEqual($date->getMonthName(), "April");
     $this->assertEqual($date->getNumDaysInMonth(), 30);
     /**
      * Day
      */
     $this->assertEqual($date->getDay(), 23);
     $this->assertEqual($date->getYearDay(), 112);
     $this->assertEqual($date->getFirstDayOfMonth()->__toString(), "04/01/2009");
     $this->assertEqual($date->getFirstDayOfMonth()->format("l"), "Wednesday");
     $this->assertEqual($date->getLastDayOfMonth()->__toString(), "04/30/2009");
     $this->assertEqual($date->getLastDayOfMonth()->format("l"), "Thursday");
     // find the xth weekday (mon-sun) of the month
     $this->assertEqual($date->getXthWeekdayOfMonth(2)->__toString(), "04/09/2009");
     // find the second Thursday of the month (Because 4/23/2009 was on a Thursday, the weekday defaults to that. The year defaults to 2009 for basically the same reason)
     $this->assertEqual($date->getXthWeekdayOfMonth(2, "Monday")->__toString(), "04/13/2009");
     // find the second monday of the month (month defaults to april because that's what $date is currently set to)
     $this->assertEqual($date->getXthWeekdayOfMonth(2, "Monday", "January")->__toString(), "01/12/2009");
     // find the second monday in January (year defaults to 2009)
     $this->assertEqual($date->getXthWeekdayOfMonth(2, "Monday", "January", 2008)->__toString(), "01/14/2008");
     // find the second Monday in January, 2008
     // now try negatives and positives
     $this->assertEqual($date->getXthWeekdayOfMonth(-2)->__toString(), "04/23/2009");
     // get the second to last Thursday of the month
     $this->assertEqual($date->getXthWeekdayOfMonth("-2")->__toString(), "04/23/2009");
     // get the second to last Thursday of the month
     $this->assertEqual($date->getXthWeekdayOfMonth(+2)->__toString(), "04/09/2009");
     // surprisingly, this works... interesting...
     $this->assertEqual($date->getXthWeekdayOfMonth("+2")->__toString(), "04/09/2009");
     // we can also use numbers instead of spelling out the names of weekdays and months. For the weekday part, use 0 for Sunday through 6 for Saturday (the same as PHP's date function's "w" metacharacter)
     $this->assertEqual($date->getXthWeekdayOfMonth(2, 1)->__toString(), "04/13/2009");
     // second monday
     $this->assertEqual($date->getXthWeekdayOfMonth(2, 1, 1)->__toString(), "01/12/2009");
     // second monday in january
     $this->assertEqual($date->getXthWeekdayOfMonth(-2, 1)->__toString(), "04/20/2009");
     // second to last monday in april
     /**
      * Year
      */
     $this->assertEqual($date->getYear(), 2009);
     /**
      * Week
      */
     $this->assertEqual($date->getWeekDay(), 4);
     $this->assertEqual($date->getWeekDayName(), "Thursday");
     $this->assertEqual($date->getWeekOfYear(), 17);
     /**
      * Unix Timestamp
      */
     $this->assertEqual($date->getUnixTimestamp(), gmmktime(0, 0, 0, 4, 23, 2009));
 }
Example #3
0
 /**
  * Determine the number or Tuesdays (or whatever day of the week this date is) since the
  * beginning or end of the month.
  * @param integer $xth A positive or negative number that determines which weekday of the month we want
  * @param string|integer $weekday Either Sunday-Saturday or 0-6 to specify the weekday we want
  * @param string|integer $month Either January-December or 1-12 to specify the month we want
  * @param integer $year A valid year to specify which year we want
  */
 public function getXthWeekdayOfMonth($xth, $weekday = null, $month = null, $year = null)
 {
     $negpos = substr($xth, 0, 1);
     if ($negpos == "+" || $negpos == "-") {
         $xth = (int) substr($xth, 1);
     } else {
         $negpos = "+";
     }
     if (is_null($weekday)) {
         $weekday = $this->getWeekday();
     }
     if (ctype_digit((string) $weekday)) {
         if (!array_key_exists($weekday, $this->weekdays)) {
             throw new qCal_Date_Exception_InvalidWeekday("\"{$weekday}\" is not a valid weekday.");
         }
     } else {
         $weekday = strtolower($weekday);
         if (!in_array($weekday, $this->weekdays)) {
             throw new qCal_Date_Exception_InvalidWeekday("\"{$weekday}\" is not a valid weekday.");
         }
         $wdays = array_flip($this->weekdays);
         $weekday = $wdays[$weekday];
     }
     if (is_null($month)) {
         $month = $this->getMonth();
     }
     if (ctype_digit((string) $month)) {
         if (!array_key_exists($month, $this->months)) {
             throw new qCal_Date_Exception_InvalidMonth("\"{$month}\" is not a valid month.");
         }
     } else {
         $month = strtolower($month);
         if (!in_array($month, $this->months)) {
             throw new qCal_Date_Exception_InvalidMonth("\"{$month}\" is not a valid month.");
         }
         $mons = array_flip($this->months);
         $month = $mons[$month];
     }
     if (is_null($year)) {
         $year = $this->getYear();
     }
     if (!ctype_digit((string) $year) || strlen($year) != 4) {
         throw new qCal_Date_Exception_InvalidYear("\"{$year}\" is not a valid year.");
     }
     // now, using the year, month and numbered weekday, we need to find the actual day of the month...
     $firstofmonth = new qCal_Date($year, $month, 1);
     $numdaysinmonth = $firstofmonth->getNumDaysInMonth();
     $numweekdays = 0;
     // the number of weekdays that have occurred (in the loop)
     $foundday = false;
     if ($negpos == "+") {
         $day = 1;
         $wday = $firstofmonth->getWeekday();
         // while we are in the current month, loop
         while ($day <= $numdaysinmonth) {
             // if the specified weekday == the current week day in the loop
             if ($weekday == $wday) {
                 $numweekdays++;
                 if ($numweekdays == $xth) {
                     // break out of the loop, we've found the right day! yay!
                     $foundday = $day;
                     break;
                 }
             }
             if ($wday == 6) {
                 $wday = 0;
             } else {
                 $wday++;
             }
             $day++;
         }
     } else {
         $day = $numdaysinmonth;
         $lastofmonth = $firstofmonth->getLastDayOfMonth();
         $wday = $lastofmonth->getWeekday();
         while ($day >= 1) {
             if ($weekday == $wday) {
                 $numweekdays++;
                 if ($numweekdays == $xth) {
                     // break out of the loop, we've found the right day! yay!
                     $foundday = $day;
                     break;
                 }
             }
             if ($wday == 0) {
                 $wday = 6;
             } else {
                 $wday--;
             }
             $day--;
         }
     }
     if ($foundday && checkdate($month, $day, $year)) {
         $date = new qCal_Date($year, $month, $day);
     } else {
         if ($day == 32) {
             throw new qCal_DateTime_Exception_InvalidDate("You have specified an incorrect number of days for qCal_Date::getXthWeekdayOfMonth()");
         } else {
             throw new qCal_DateTime_Exception_InvalidDate("You have entered an invalid date.");
         }
     }
     return $date;
 }