/** * Produce an iCalendar format DURATION for the difference between this an another iCalDate * * @param date $from The start of the period * @return string The date difference, as an iCalendar duration format */ public function DateDifference($from) { if (!is_object($from)) { $from = new iCalDate($from); } if ($from->_epoch < $this->_epoch) { /** One way to simplify is to always go for positive differences */ return "-" . $from->DateDifference($self); } // if ( $from->_yy == $this->_yy && $from->_mo == $this->_mo ) { /** Also somewhat simpler if we can use seconds */ $diff = $from->_epoch - $this->_epoch; $result = ""; if ($diff >= 86400) { $result = intval($diff / 86400); $diff = $diff % 86400; if ($diff == 0 && $result % 7 == 0) { // Duration is an integer number of weeks. $result .= intval($result / 7) . "W"; return $result; } $result .= "D"; } $result = "P" . $result . "T"; if ($diff >= 3600) { $result .= intval($diff / 3600) . "H"; $diff = $diff % 3600; } if ($diff >= 60) { $result .= intval($diff / 60) . "M"; $diff = $diff % 60; } if ($diff > 0) { $result .= intval($diff) . "S"; } return $result; // } /** * From an intense reading of RFC2445 it appears that durations which are not expressible * in Weeks/Days/Hours/Minutes/Seconds are invalid. * ==> This code is not needed then :-) $yy = $from->_yy - $this->_yy; $mo = $from->_mo - $this->_mo; $dd = $from->_dd - $this->_dd; $hh = $from->_hh - $this->_hh; $mi = $from->_mi - $this->_mi; $ss = $from->_ss - $this->_ss; if ( $ss < 0 ) { $mi -= 1; $ss += 60; } if ( $mi < 0 ) { $hh -= 1; $mi += 60; } if ( $hh < 0 ) { $dd -= 1; $hh += 24; } if ( $dd < 0 ) { $mo -= 1; $dd += $this->DaysInMonth(); } // Which will use $this->_(mo|yy) - seemingly sensible if ( $mo < 0 ) { $yy -= 1; $mo += 12; } $result = ""; if ( $yy > 0) { $result .= $yy."Y"; } if ( $mo > 0) { $result .= $mo."M"; } if ( $dd > 0) { $result .= $dd."D"; } $result .= "T"; if ( $hh > 0) { $result .= $hh."H"; } if ( $mi > 0) { $result .= $mi."M"; } if ( $ss > 0) { $result .= $ss."S"; } return $result; */ }
/** * Processes the array of $relative_days to $base and removes any * which are not within the scope of our rule. */ function WithinScope($base, $relative_days) { $ok_days = array(); $ptr = $this->_current; // dbg_error_log( "RRule", " WithinScope: Processing list of %d days relative to %s", count($relative_days), $base->Render() ); foreach ($relative_days as $day => $v) { $test = new iCalDate($base); $days_in_month = $test->DaysInMonth(); // dbg_error_log( "RRule", " WithinScope: Testing for day %d based on %s, with %d days in month", $day, $test->Render(), $days_in_month ); if ($day > $days_in_month) { $test->SetMonthDay($days_in_month); $test->AddDays(1); $day -= $days_in_month; $test->SetMonthDay($day); } else { if ($day < 1) { $test->SetMonthDay(1); $test->AddDays(-1); $days_in_month = $test->DaysInMonth(); $day += $days_in_month; $test->SetMonthDay($day); } else { $test->SetMonthDay($day); } } // dbg_error_log( "RRule", " WithinScope: Testing if %s is within scope", count($relative_days), $test->Render() ); if (isset($this->_part['UNTIL']) && $test->GreaterThan($this->_part['UNTIL'])) { $this->_finished = true; return $ok_days; } // if ( $this->_current >= 0 && $test->LessThan($this->_dates[$this->_current]) ) continue; if (!$test->LessThan($this->_first)) { // dbg_error_log( "RRule", " WithinScope: Looks like %s is within scope", $test->Render() ); $ok_days[$day] = $test; $ptr++; } if (isset($this->_part['COUNT']) && $ptr >= $this->_part['COUNT']) { $this->_finished = true; return $ok_days; } } return $ok_days; }