/** * Calculates the date of the Nth weekday of the month, * such as the second Saturday of January 2000. * * @param string occurance: 1=first, 2=second, 3=third, etc. * @param string dayOfWeek: 0=Sunday, 1=Monday, etc. * @param string year in format CCYY * @param string month in format MM * @param string format for returned date * * @access public * * @return string date in given format */ function NWeekdayOfMonth($occurance, $dayOfWeek, $month, $year, $format = "%Y%m%d") { $year = sprintf("%04d", $year); $month = sprintf("%02d", $month); $DOW1day = sprintf("%02d", ($occurance - 1) * 7 + 1); $DOW1 = Date_Calc::dayOfWeek($DOW1day, $month, $year); $wdate = ($occurance - 1) * 7 + 1 + (7 + $dayOfWeek - $DOW1) % 7; if ($wdate > Date_Calc::daysInMonth($month, $year)) { return -1; } else { return Date_Calc::dateFormat($wdate, $month, $year, $format); } }
/** * Calculates the date of the Nth weekday of the month, * such as the second Saturday of January 2000. * * @param string occurance: 1=first, 2=second, 3=third, etc. * @param string dayOfWeek: 0=Sunday, 1=Monday, etc. * @param string year in format CCYY * @param string month in format MM * @param string format for returned date * * @access public * * @return string date in given format */ public function NWeekdayOfMonth($occurance, $dayOfWeek, $month, $year, $format = "%Y-%m-%d") { $year = sprintf("%04d", $year); $month = sprintf("%02d", $month); $DOW1day = sprintf("%02d", ($occurance - 1) * 7 + 1); $DOW1 = Date_Calc::dayOfWeek($DOW1day, $month, $year); $wdate = ($occurance - 1) * 7 + 1 + (7 + $dayOfWeek - $DOW1) % 7; if ($wdate > Date_Calc::daysInMonth($month, $year)) { if ($occurance == 5) { // Getting the last day overshot the month, go back a week $wdate -= 7; return Date_Calc::dateFormat($wdate, $month, $year, $format); } else { // For $occurance === 1 through 4 this is an error return -1; } } else { return Date_Calc::dateFormat($wdate, $month, $year, $format); } }
/** * Calculates the date of the Nth weekday of the month, * such as the second Saturday of January 2000 * * @param int $week the number of the week to get * (1 = first, etc. Also can be 'last'.) * @param int $dow the day of the week (0 = Sunday) * @param int $month the month * @param int $year the year. Use the complete year instead of the * abbreviated version. E.g. use 2005, not 05. * @param string $format the string indicating how to format the output * * @return string the date in the desired format * @access public * @static */ function nWeekdayOfMonth($week, $dow, $month, $year, $format = DATE_CALC_FORMAT) { if (is_numeric($week)) { $DOW1day = ($week - 1) * 7 + 1; $DOW1 = Date_Calc::dayOfWeek($DOW1day, $month, $year); $wdate = ($week - 1) * 7 + 1 + (7 + $dow - $DOW1) % 7; if ($wdate > Date_Calc::daysInMonth($month, $year)) { return -1; } else { return Date_Calc::dateFormat($wdate, $month, $year, $format); } } elseif ($week == 'last' && $dow < 7) { $lastday = Date_Calc::daysInMonth($month, $year); $lastdow = Date_Calc::dayOfWeek($lastday, $month, $year); $diff = $dow - $lastdow; if ($diff > 0) { return Date_Calc::dateFormat($lastday - (7 - $diff), $month, $year, $format); } else { return Date_Calc::dateFormat($lastday + $diff, $month, $year, $format); } } else { return -1; } }
/** * Is the given date/time in DST for this time zone * * Works for all years, positive and negative. Possible problems * are that when the clocks go forward, there is an invalid hour * which is skipped. If a time in this hour is specified, this * function returns an error. When the clocks go back, there is an * hour which is repeated, that is, the hour is gone through twice - * once in Summer time and once in standard time. If this time * is specified, then this function returns '$pb_repeatedhourdefault', * because there is no way of knowing which is correct, and * both possibilities are equally likely. * * Also bear in mind that the clocks go forward at the instant of * the hour specified in the time-zone array below, and if this * exact hour is specified then the clocks have actually changed, * and this function reflects this. * * @param object $pm_date Date object to test or array of * day, month, year, seconds past * midnight * @param bool $pb_repeatedhourdefault value to return if repeated hour is * specified (defaults to false) * * @return bool true if this date is in Summer time for this time * zone * @access public */ function inDaylightTime($pm_date, $pb_repeatedhourdefault = false) { if (!$this->hasdst) { return false; } if (is_a($pm_date, "Date")) { $hn_day = $pm_date->getDay(); $hn_month = $pm_date->getMonth(); $hn_year = $pm_date->getYear(); $hn_seconds = $pm_date->getSecondsPastMidnight(); } else { $hn_day = $pm_date[0]; $hn_month = $pm_date[1]; $hn_year = $pm_date[2]; $hn_seconds = $pm_date[3]; // seconds past midnight } if ($this->on_summertimestartmonth < $this->on_summertimeendmonth && $hn_month >= $this->on_summertimestartmonth && $hn_month <= $this->on_summertimeendmonth || $this->on_summertimestartmonth > $this->on_summertimeendmonth && $hn_month >= $this->on_summertimestartmonth && $hn_month <= $this->on_summertimeendmonth) { if ($hn_month == $this->on_summertimestartmonth) { $hn_startday = $this->getSummerTimeLimitDay($this->os_summertimestartday, $this->on_summertimestartmonth, $hn_year); if ($hn_day < $hn_startday) { return false; } else { if ($hn_day > $hn_startday) { return true; } else { if (($hn_gmt = $hn_seconds * 1000 - $this->offset) - $this->on_summertimeoffset >= $this->on_summertimestarttime) { return true; } else { if (($hn_gmt = $hn_seconds * 1000 - $this->offset) >= $this->on_summertimestarttime) { return PEAR::raiseError("Invalid time specified for date '" . Date_Calc::dateFormat($hn_day, $hn_month, $hn_year, "%Y-%m-%d") . "'", DATE_ERROR_INVALIDTIME); } else { return false; } } } } } else { if ($hn_month == $this->on_summertimeendmonth) { $hn_endday = $this->getSummerTimeLimitDay($this->os_summertimeendday, $this->on_summertimeendmonth, $hn_year); if ($hn_day < $hn_endday) { return true; } else { if ($hn_day > $hn_endday) { return false; } else { if (($hn_gmt = $hn_seconds * 1000 - $this->offset) - $this->on_summertimeoffset >= $this->on_summertimeendtime) { return false; } else { if ($hn_gmt >= $this->on_summertimeendtime) { // There is a 50:50 chance that it's Summer time, but there // is no way of knowing (the hour is repeated), so return // default: // return $pb_repeatedhourdefault; } else { return true; } } } } } } return true; } return false; }
/** * Sets all the fields of the date object (day, month, year, hour, minute * and second) * * If specified year forms an invalid date, then PEAR error will be * returned. Note that setting each of these fields separately * may unintentionally return a PEAR error if a transitory date is * invalid between setting these fields. * * N.B. if the repeated hour, due to the clocks going back, is specified, * the default is to assume local standard time. * * @param int $pn_day the day * @param int $pn_month the month * @param int $pn_year the year * @param int $pn_hour the hour * @param int $pn_minute the minute * @param mixed $pm_second the second as integer or float * @param bool $pb_repeatedhourdefault whether to assume Summer time if a * repeated hour is specified * (defaults to false) * * @return void * @access public * @see Date::setDayMonthYear(), Date::setHourMinuteSecond() * @since Method available since Release 1.5.0 */ function setDateTime($pn_day, $pn_month, $pn_year, $pn_hour, $pn_minute, $pm_second, $pb_repeatedhourdefault = false) { if (!Date_Calc::isValidDate($d, $m, $y)) { return PEAR::raiseError("'" . Date_Calc::dateFormat($d, $m, $y, "%Y-%m-%d") . "' is invalid calendar date", DATE_ERROR_INVALIDDATE); } else { // Split second into integer and part-second: // if (is_float($pm_second)) { $hn_second = intval($pm_second); $hn_partsecond = $pm_second - $hn_second; } else { $hn_second = (int) $pm_second; $hn_partsecond = 0.0; } $this->setLocalTime($d, $m, $y, $h, $m, $hn_second, $hn_partsecond, $pb_repeatedhourdefault); } }
function calculateEvents($days, $events, $viewtype) { $date = postcalendar_getDate(); $cy = substr($date, 0, 4); $cm = substr($date, 4, 2); $cd = substr($date, 6, 2); foreach ($events as $event) { // get the name of the topic $topicname = pcGetTopicName($event['topic']); // parse the event start date list($esY, $esM, $esD) = explode('-', $event['eventDate']); // grab the recurring specs for the event $event_recurrspec = @unserialize($event['recurrspec']); // determine the stop date for this event if ($event['endDate'] == '0000-00-00') { $stop = $end_date; // <--- this isn't previously defined !! } else { $stop = $event['endDate']; } // here the start_date value is set to whatever comes in // on postcalendar_getDate() which is not always the first // date of the days array -- JRM $start_date = "{$cy}-{$cm}-{$cd}"; // here we've made the start_date equal to the first date // of the days array, makes sense, right? -- JRM $days_keys = array_keys($days); $start_date = $days_keys[0]; // Optimization of the stop date to not be much later than required. $tmpsecs = strtotime($start_date); if ($viewtype == 'day') { $tmpsecs += 3 * 24 * 3600; } else { if ($viewtype == 'week') { $tmpsecs += 9 * 24 * 3600; } else { if ($viewtype == 'month') { $tmpsecs += 34 * 24 * 3600; } else { $tmpsecs += 367 * 24 * 3600; } } } $tmp = date('Y-m-d', $tmpsecs); if ($stop > $tmp) { $stop = $tmp; } $eventD = $event['eventDate']; $eventS = $event['startTime']; switch ($event['recurrtype']) { //============================================================== // Events that do not repeat only have a startday //============================================================== case NO_REPEAT: if (isset($days[$event['eventDate']])) { array_push($days[$event['eventDate']], $event); if ($viewtype == "week") { //echo "non repeating date eventdate: $eventD startime:$eventS block #: " . getBlockTime($eventS) ."<br />"; fillBlocks($eventD, $days); //echo "for $eventD loading " . getBlockTime($eventS) . "<br /><br />"; $gbt = getBlockTime($eventS); $days[$eventD]['blocks'][$gbt][$eventD][] = $event; //echo "event is: " . print_r($days[$eventD]['blocks'][$gbt],true) . " <br />"; //echo "begin printing blocks for $eventD<br />"; //print_r($days[$eventD]['blocks']); //echo "end printing blocks<br />"; } } break; //============================================================== // Find events that repeat at a certain frequency // Every,Every Other,Every Third,Every Fourth // Day,Week,Month,Year,MWF,TR,M-F,SS //============================================================== //============================================================== // Find events that repeat at a certain frequency // Every,Every Other,Every Third,Every Fourth // Day,Week,Month,Year,MWF,TR,M-F,SS //============================================================== case REPEAT: $rfreq = $event_recurrspec['event_repeat_freq']; $rtype = $event_recurrspec['event_repeat_freq_type']; $exdate = $event_recurrspec['exdate']; // this attribute follows the iCalendar spec http://www.ietf.org/rfc/rfc2445.txt // we should bring the event up to date to make this a tad bit faster // any ideas on how to do that, exactly??? dateToDays probably. $nm = $esM; $ny = $esY; $nd = $esD; $occurance = Date_Calc::dateFormat($nd, $nm, $ny, '%Y-%m-%d'); while ($occurance < $start_date) { $occurance =& __increment($nd, $nm, $ny, $rfreq, $rtype); list($ny, $nm, $nd) = explode('-', $occurance); } while ($occurance <= $stop) { if (isset($days[$occurance])) { // check for date exceptions before pushing the event into the days array -- JRM $excluded = false; if (isset($exdate)) { foreach (explode(",", $exdate) as $exception) { // occurrance format == yyyy-mm-dd // exception format == yyyymmdd if (preg_replace("/-/", "", $occurance) == $exception) { $excluded = true; } } } // push event into the days array if ($excluded == false) { array_push($days[$occurance], $event); } if ($viewtype == "week") { fillBlocks($occurance, $days); //echo "for $occurance loading " . getBlockTime($eventS) . "<br /><br />"; $gbt = getBlockTime($eventS); $days[$occurance]['blocks'][$gbt][$occurance][] = $event; //echo "begin printing blocks for $eventD<br />"; //print_r($days[$occurance]['blocks']); //echo "end printing blocks<br />"; } } $occurance =& __increment($nd, $nm, $ny, $rfreq, $rtype); list($ny, $nm, $nd) = explode('-', $occurance); } break; //============================================================== // Find events that repeat on certain parameters // On 1st,2nd,3rd,4th,Last // Sun,Mon,Tue,Wed,Thu,Fri,Sat // Every N Months //============================================================== //============================================================== // Find events that repeat on certain parameters // On 1st,2nd,3rd,4th,Last // Sun,Mon,Tue,Wed,Thu,Fri,Sat // Every N Months //============================================================== case REPEAT_ON: $rfreq = $event_recurrspec['event_repeat_on_freq']; $rnum = $event_recurrspec['event_repeat_on_num']; $rday = $event_recurrspec['event_repeat_on_day']; $exdate = $event_recurrspec['exdate']; // this attribute follows the iCalendar spec http://www.ietf.org/rfc/rfc2445.txt //============================================================== // Populate - Enter data into the event array //============================================================== $nm = $esM; $ny = $esY; $nd = $esD; if (isset($event_recurrspec['rt2_pf_flag']) && $event_recurrspec['rt2_pf_flag']) { $nd = 1; } // Added by epsdky 2016. // $nd will sometimes be 29, 30 or 31 and if used in the mktime functions // below a problem with overfow will occur so it is set to 1 to prevent this. // (for rt2 appointments set prior to fix it remains unchanged). This can be done // since $nd has no influence past the mktime functions - epsdky 2016. // make us current while ($ny < $cy) { $occurance = date('Y-m-d', mktime(0, 0, 0, $nm + $rfreq, $nd, $ny)); list($ny, $nm, $nd) = explode('-', $occurance); } // populate the event array while ($ny <= $cy) { $dnum = $rnum; // get day event repeats on do { $occurance = Date_Calc::NWeekdayOfMonth($dnum--, $rday, $nm, $ny, $format = "%Y-%m-%d"); } while ($occurance === -1); if (isset($days[$occurance]) && $occurance <= $stop) { // check for date exceptions before pushing the event into the days array -- JRM $excluded = false; if (isset($exdate)) { foreach (explode(",", $exdate) as $exception) { // occurrance format == yyyy-mm-dd // exception format == yyyymmdd if (preg_replace("/-/", "", $occurance) == $exception) { $excluded = true; } } } // push event into the days array if ($excluded == false) { array_push($days[$occurance], $event); } if ($viewtype == "week") { fillBlocks($occurance, $days); //echo "for $occurance loading " . getBlockTime($eventS) . "<br /><br />"; $gbt = getBlockTime($eventS); $days[$occurance]['blocks'][$gbt][$occurance][] = $event; } } $occurance = date('Y-m-d', mktime(0, 0, 0, $nm + $rfreq, $nd, $ny)); list($ny, $nm, $nd) = explode('-', $occurance); } break; case REPEAT_DAYS: $rfreq = $event_recurrspec['event_repeat_freq']; $rtype = $event_recurrspec['event_repeat_freq_type']; $exdate = $event_recurrspec['exdate']; // this attribute follows the iCalendar spec http://www.ietf.org/rfc/rfc2445.txt // we should bring the event up to date to make this a tad bit faster // any ideas on how to do that, exactly??? dateToDays probably. $nm = $esM; $ny = $esY; $nd = $esD; $occurance = Date_Calc::dateFormat($nd, $nm, $ny, '%Y-%m-%d'); while ($occurance < $start_date) { $occurance =& __increment($nd, $nm, $ny, $rfreq, $rtype); list($ny, $nm, $nd) = explode('-', $occurance); } while ($occurance <= $stop) { if (isset($days[$occurance])) { // check for date exceptions before pushing the event into the days array -- JRM $excluded = false; if (isset($exdate)) { foreach (explode(",", $exdate) as $exception) { // occurrance format == yyyy-mm-dd // exception format == yyyymmdd if (preg_replace("/-/", "", $occurance) == $exception) { $excluded = true; } } } // push event into the days array if ($excluded == false) { array_push($days[$occurance], $event); } if ($viewtype == "week") { fillBlocks($occurance, $days); //echo "for $occurance loading " . getBlockTime($eventS) . "<br /><br />"; $gbt = getBlockTime($eventS); $days[$occurance]['blocks'][$gbt][$occurance][] = $event; //echo "begin printing blocks for $eventD<br />"; //print_r($days[$occurance]['blocks']); //echo "end printing blocks<br />"; } } $occurance =& __increment($nd, $nm, $ny, $rfreq, $rtype); list($ny, $nm, $nd) = explode('-', $occurance); } break; } // <- end of switch($event['recurrtype']) } // <- end of foreach($events as $event) return $days; }
/** * Generate the HTML_Table object of the calendar * * @param day day of the calendar to generate, null = today's day * @param month month of the calendar to generate, null = today's month * @param year year of the calendar to generate, null = today's year * * @access public * @return the HTML_Table object of the calendar */ function generateTable($day = null, $month = null, $year = null) { if (empty($year)) { $year = Date_Calc::dateNow('%Y'); } if (empty($month)) { $month = Date_Calc::dateNow('%m'); } if (empty($day)) { $day = Date_Calc::dateNow('%d'); } $year = sprintf('%04d', $year); $month = sprintf('%02d', $month); $day = sprintf('%02d', $day); // get month structure for generating calendar $month_cal = Date_Calc::getCalendarMonth($month, $year, '%E'); $this->_todayDays = Date_Calc::dateFormat(null, null, null, '%E'); $this->_thisMonth = Date_Calc::dateFormat($day, $month, $year, '%m'); $row = 0; $table = new HTML_Table($this->_attributes['table']); $table->addRow(array($this->drawTitle($day, $month, $year))); $table->setRowAttributes($row, $this->_attributes['title']); $row++; for ($col = 0; $col < 7; $col++) { $table->setCellContents($row, $col, $this->drawWeekDayText($col), 'TH'); } $table->setRowAttributes($row++, $this->_attributes['weekday']); for ($week = 0; $week < count($month_cal); $week++) { for ($col = 0; $col < 7; $col++) { $table->setCellContents($row, $col, $this->drawCell($month_cal[$week][$col], $week, $col)); $type = $this->getType($month_cal[$week][$col]); $table->setCellAttributes($row, $col, $this->_attributes['cell']); $table->updateCellAttributes($row, $col, $this->_attributes['cell_' . $type]); } $row++; } return $table; }
/** * Create recurrences. * This is a common function for the most common recurrence types: * once per week/year, etc. */ public function MakeRecurrences() { global $_EV_CONF; list($year, $month, $day) = explode('-', $this->dt_start); // Get the date of this occurrence. The date is stored as two // values: 0 = the scheduled date for this occurrence, 1 = the // actual date in case it's rescheduled due to a weekend. // Keeping the occurrence is based on (1), scheduling the next // occurrence is based on (0). $thedate = Date_Calc::dateFormat($day, $month, $year, '%Y-%m-%d'); $occurrence = array($thedate, $thedate); // Get any occurrences before our stop. Keep these. $count = 0; while ($occurrence[1] <= $this->event->rec_data['stop'] && $occurrence[1] >= '1971-01-01' && $count < $_EV_CONF['max_repeats']) { $this->storeEvent($occurrence[1]); $count++; $occurrence = $this->GetNextDate($day, $month, $year); while ($occurrence[1] === NULL) { if ($occurrence === NULL) { break 2; } list($year, $month, $day) = explode('-', $occurrence[0]); $occurrence = $this->GetNextDate($day, $month, $year); } list($year, $month, $day) = explode('-', $occurrence[0]); } return $this->events; }
echo "{$test_name} failed. Expect:\n"; print_r($expect); echo "Actual:\n"; print_r($actual); } } else { if ($expect != $actual) { echo "{$test_name} failed. Expect: {$expect}. Actual: {$actual}\n"; } } } if (php_sapi_name() != 'cli') { echo "<pre>\n"; } compare('20001122', Date_Calc::dateFormat(22, 11, 2000, '%Y%m%d'), 'dateFormat'); compare('20001122', Date_Calc::dateFormat('22', '11', '2000', '%Y%m%d'), 'dateFormat str'); compare('2001', Date_Calc::defaultCentury('1'), 'defaultCentury 1 str'); compare('2001', Date_Calc::defaultCentury(1), 'defaultCentury 1'); compare('1960', Date_Calc::defaultCentury(60), 'defaultCentury 2'); compare('2010', Date_Calc::defaultCentury(10), 'defaultCentury 3'); compare(2451871, Date_Calc::dateToDays('22', '11', '2000'), 'dateToDays str'); compare(2451871, Date_Calc::dateToDays(22, 11, 2000), 'dateToDays'); compare('20001122', Date_Calc::daysToDate(2451871), 'daysToDate'); compare('2000-47-3', Date_Calc::gregorianToISO('22', '11', '2000'), 'gregorianToISO str'); compare('2000-47-3', Date_Calc::gregorianToISO(22, 11, 2000), 'gregorianToISO'); compare(2451716.56767, Date_Calc::dateSeason('SUMMERSOLSTICE', 2000), 'dateSeason'); compare(date('Ymd'), Date_Calc::dateNow(), 'dateNow'); compare(date('Y'), Date_Calc::getYear(), 'getYear'); compare(date('m'), Date_Calc::getMonth(), 'getMonth'); compare(date('d'), Date_Calc::getDay(), 'getDay'); compare(327, Date_Calc::dayOfYear(22, 11, 2000), 'dayOfYear');
/** * Calculates the date of the Nth weekday of the month, * such as the second Saturday of January 2000 * * @param int $week the number of the week to get * (1 to 5. Also can be 'last'.) * @param int $dow the day of the week (0 = Sunday) * @param int $month the month * @param int $year the year. Use the complete year instead of the * abbreviated version. E.g. use 2005, not 05. * @param string $format the string indicating how to format the output * * @return string the date in the desired format * @access public * @static */ function nWeekDayOfMonth($week, $dow, $month, $year, $format = DATE_CALC_FORMAT) { if (is_numeric($week) && ($week < 1 || $week > 5) || !is_numeric($week) && $week != "last") { return PEAR::raiseError("Invalid week value '{$week}', only 1-5 or 'last' accepted"); } if ($dow < 0 || $dow > 6) { return PEAR::raiseError("Invalid dow value '{$dow}', only 0-6 accepted"); } if ($month < 1 || $month > 12) { return PEAR::raiseError("Invalid month value '{$month}'"); } if (is_numeric($week)) { // the weekday of first day of month "1" $DOW1 = Date_Calc::dayOfWeek(1, $month, $year); // finds the sunday $sunday = ($week - 1) * 7 + 1; if ($DOW1 > 0) { $sunday += 7 - $DOW1; } // adjust the sunday with dow addition $wdate = $sunday + $dow; if ($wdate > Date_Calc::daysInMonth($month, $year)) { return -1; } else { return Date_Calc::dateFormat($wdate, $month, $year, $format); } } elseif ($week == 'last' && $dow < 7) { $lastday = Date_Calc::daysInMonth($month, $year); $lastdow = Date_Calc::dayOfWeek($lastday, $month, $year); $diff = $dow - $lastdow; if ($diff > 0) { return Date_Calc::dateFormat($lastday - (7 - $diff), $month, $year, $format); } else { return Date_Calc::dateFormat($lastday + $diff, $month, $year, $format); } } else { return -1; } }