/** * Check a qCal_Date object to see if it falls within the rules specified * when this object was created (or added later actually). * @param qCal_Date The date that you want to check * @return boolean True if the date falls within the ruleset * @access public */ public function checkDate(qCal_Date $date) { $byDay = $this->getValues(); foreach ($byDay as $wday) { $char1 = substr($wday, 0, 1); $cwday = strtoupper(substr($date->getWeekDayName(), 0, 2)); if (ctype_digit($char1) || $char1 == "-" || $char1 == "+") { // if the first character is a digit or a plus or minus, we // need to check that date is a specific weekday of the month if (preg_match('/([+-]?)([0-9]+)([a-z]+)/i', $wday, $matches)) { list($whole, $sign, $dig, $wd) = $matches; // find out if this day matches the specific weekday of month $xth = (int) ($sign . $dig); // @todo Make sure that getXthWeekDayOfMonth doesn't need // to be passed any month or date here... $dtWdSpecific = $date->getXthWeekdayOfMonth($xth, $wd); if ($dtWdSpecific->__toString() == $date->__toString()) { return true; } } } else { if ($wday == $cwday) { return true; } } } return false; }
public function testTimezoneSetsServerTimezoneToGMT() { $timezone = qCal_Timezone::factory(array("foo" => "bar", "name" => "FooBar/Assmunch", "abbreviation" => "t**s", "offsetSeconds" => "-28800")); // this way, our timezone component works independently of the server timezone. // if I can find a way to work with times without having php's functions adjust the output // then I will. otherwise, I'll just have to set the timezone to GMT // date_default_timezone_set("GMT"); $date = gmdate("Y-m-d H:i:s", 0); $date = qCal_Date::gmgetdate(0); }
/** * Check a qCal_Date object to see if it falls within the rules specified * when this object was created (or added later actually). * @param qCal_Date The date that you want to check * @return boolean True if the date falls within the ruleset * @access public */ public function checkDate(qCal_Date $date) { return (bool) in_array($date->getDay(), $this->getValues()); }
/** * Test that you can determine the amount of days in the year (usually 365, but 366 on leap-year) */ public function testNumDaysInYear() { $date = new qCal_Date(2009, 4, 23); $this->assertEqual($date->getNumDaysInYear(), 365); $date2 = new qCal_Date(2008, 4, 23); $this->assertTrue($date2->getNumDaysInYear(), 366); }
/** * This converts to a qCal_Date for internal storage */ protected function doCast($value) { $date = qCal_Date::factory($value); return $date; }
/** * Test that date data is handled right */ public function testRawDate() { $value = new qCal_Value_Date('2009-04-23'); $this->assertEqual($value->getValue(), qCal_Date::factory('2009-04-23')); }
/** * Provided a date/time object, use this recurrence's rules to determine * all of the recurrence times for the date and return them in an array. * @param qCal_Date The date object to find time recurrences for * @return array A list of time recurrences for the specified date/time * @access protected * @todo I don't really like the way this is done. Definitely a code smell here. * Each of the rules should do their own logic. Something like: * $seconds = $bySecond->getTimeInstances(); * $minutes = $byMinute->getTimeInstances($seconds); * $hours = $byHour->getTimeInstances($minutes); */ protected function findTimeRecurrences(qCal_Date $date) { // find all of the bySeconds $seconds = array(); if ($this->hasRule('qCal_DateTime_Recur_Rule_BySecond')) { $seconds = $this->getRule('qCal_DateTime_Recur_Rule_BySecond')->getValues(); sort($seconds); } else { $seconds = array($this->getStart()->getTime()->getSecond()); } // find all of the byMinutes $minutes = array(); if ($this->hasRule('qCal_DateTime_Recur_Rule_ByMinute')) { $minutesRules = $this->getRule('qCal_DateTime_Recur_Rule_ByMinute')->getValues(); sort($minutesRules); } else { $minutesRules = array($this->getStart()->getTime()->getMinute()); } foreach ($minutesRules as $minute) { $minutes[$minute] = $seconds; } // find all of the byHours $hours = array(); if ($this->hasRule('qCal_DateTime_Recur_Rule_ByHour')) { $hoursRules = $this->getRule('qCal_DateTime_Recur_Rule_ByHour')->getValues(); sort($hoursRules); } else { $hoursRules = array($this->getStart()->getTime()->getHour()); } foreach ($hoursRules as $hour) { $hours[$hour] = $minutes; } // create an array to store times $times = array(); foreach ($hours as $hour => $minutes) { foreach ($minutes as $minute => $seconds) { foreach ($seconds as $second) { try { // try to build a date/time object $datetime = new qCal_DateTime($date->getYear(), $date->getMonth(), $date->getDay(), $hour, $minute, $second); $times[$datetime->format('YmdHis')] = $datetime; } catch (qCal_DateTime_Exception_InvalidTime $e) { // if the date/time object instantiation fails, this exception will be thrown // @todo Recover from this error and report it. Maybe catch the error and pass it to a log or something? // qCal_Log::logException($e, get_class($this)); throw $e; } } } } return $times; }
/** * Determine the number or Tuesdays (or whatever day of the week this date is) since the * beginning or end of the year. */ public function getXthWeekdayOfYear($xth, $weekday = 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($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 find the specified day by counting either forwards or backwards to the day in question $firstofyear = new qCal_Date($year, 1, 1); $numdaysinyear = $firstofyear->isLeapYear() ? 366 : 365; $numweekdays = 0; // the number of weekdays that have occurred within the loop $found = false; // whether or not the specified day has been found if ($negpos == "+") { // count forward // loop over every day of every month looking for the right one $day = 1; $wday = $firstofyear->getWeekDay(); while ($day <= $numdaysinyear) { // 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! $found = $day; break; } } if ($wday == 6) { $wday = 0; } else { $wday++; } $day++; } } else { // count backward $lastofyear = new qCal_Date($year, 12, 31); // count forward // loop over every day of every month looking for the right one $day = $numdaysinyear; $wday = $lastofyear->getWeekDay(); while ($day >= 1) { // 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! $found = $day; break; } } if ($wday == 0) { $wday = 6; } else { $wday--; } $day--; } } // @todo: Can't use checkdate here, so find another validation method... if ($found) { $date = new qCal_Date($year, 1, $found, true); // takes advantage of the rollover feature :) } else { throw new qCal_DateTime_Exception_InvalidDate("You have specified an incorrect number of days for qCal_Date::getXthWeekdayOfYear()"); } return $date; }
/** * @todo This is a god method that really should be split out into each * of the qCal_DateTime_Recur_Rule_ByXXX classes. For now I did all the logic * here to keep it simple and not confuse myself more than necessary. */ protected function doGetRecurrences($rules, $start, $end) { // an array to store recurrences $recurrences = array(); // start day, year, and month $sday = $start->format('d'); $smonth = $start->format('m'); $syear = $start->format('Y'); // end day, year, and month $eday = $end->format('d'); $emonth = $end->format('m'); $eyear = $end->format('Y'); // loop over years, by increment $year = $syear; while ($year <= $eyear) { // if byMonth is specified... if (count($this->byMonth())) { // loop over each month for ($month = 1; $month <= 12; $month++) { // if this is the start year still and we haven't reached the start month, skip ahead if ($year == $syear && $month < $smonth) { continue; } // if this is the end year and we have passed the end month, break out of loop if ($year == $eyear && $month > $emonth) { break; } // if this is not one of the bymonths, continue as well if (!in_array($month, $this->byMonth())) { continue; } // now we need to loop over each day of the month to look for byday or bymonthday $thismonth = new qCal_Date(); // used to determine total days in the current month $thismonth->setDate($year, $month, 1); $weekdays = array('MO' => 0, 'TU' => 0, 'WE' => 0, 'TH' => 0, 'FR' => 0, 'SA' => 0, 'SU' => 0); // @todo For now this only allows 1SU, SU, but not -1SU (no negatives for now) for ($day = 1; $day <= $thismonth->format('t'); $day++) { $alreadyadded = false; $date = new qCal_Date(); $date->setDate($year, $month, $day); $date->setTime(0, 0, 0); $wdname = strtoupper(substr($date->format('l'), 0, 2)); // keep track of how many of each day of the week have gone by $weekdays[$wdname]++; // if byDay is specified... // @todo this is inconsistent, I don't use the getter here because of its special functionality. // I need to either remove the special functionality or not use getters elsewhere in this method $byday = $this->byday; if (count($byday)) { // by day is broken into an array of arrays like array('TH' => 0), array('FR' => 1), array('MO' => -2) etc. // with zero meaning every instance of that particular day should be included and number meaning the Nth of that day foreach ($byday as $val) { // if at least one of this wday has gone by... $num = current($val); if ($weekdays[$wdname] > 0) { // check if it is the right week day and if a digit is specified (like 1SU) that it is checked as well if ($wdname == key($val) && ($weekdays[$wdname] == $num || $num == 0)) { $recurrences[] = $date; $alreadyadded = true; } } } } // if byMonthDay is specified... if (count($this->byMonthDay())) { foreach ($this->byMonthDay() as $mday) { // only add this day if it hasn't been added already if ($mday == $day && !$alreadyadded) { $recurrences[] = $date; } } } // now loop over each hour and add hours if (count($this->byHour())) { $hourrecurrences = array(); foreach ($this->byHour() as $hour) { $new = new qCal_Date(); $new = $new->copy($date); $new->setTime($hour, 0, 0); $hourrecurrences[] = $new; } } // now loop over byHours and add byMinutes if (count($this->byMinute())) { if (!isset($minuterecurrences)) { $minuterecurrences = array(); } foreach ($this->byMinute() as $minute) { $new = new qCal_Date(); $new = $new->copy($date); $new->setTime(0, $minute, 0); } } // now loop over byMinutes and add bySeconds } } } // if in the first year we don't find an instance, don't do the interval, just increment a year if ($year == $syear && count($recurrences)) { $year += $this->interval(); } else { $year++; } } // now loop over weeks to get byWeekNo foreach ($recurrences as $date) { // pr($date->format("r")); } // exit; return $recurrences; // for bymonth, it would make the most sense to loop over each month until the specified one // is found. Then loop over each day to find its sub-rules. // for byweekno, it would make the most sense to loop over each week until the specified one // is found. Then apply any sub-rules (actually I'm not sure how byhour and its ilk would be applied in this situation... need to read the rfc) }
public function testGetFirstAndLastDayOfMonth() { $date = new qCal_Date(2010, 1, 10); $first = $date->getFirstDayOfMonth(); // will return a qCal_Date object for January 1st, 2010 $this->assertEqual($first->__toString(), "01/01/2010"); $date = new qCal_Date(2010, 1, 10); $last = $date->getLastDayOfMonth(); // will return a qCal_Date object for January 31st, 2010 $this->assertEqual($last->__toString(), "01/31/2010"); }
/** * How many months are there left in the year? */ public function testHowManyMonthsLeftInTheYear() { $date = new qCal_Date(2010, 10, 23); $this->assertEqual($date->getNumMonthsUntilEndOfYear(), 2); }