mirror of
https://gitlab.com/davical-project/davical.git
synced 2026-04-25 15:10:13 +00:00
Lots of fixes for PHP5 and correctness. Nearly done...
This commit is contained in:
parent
c86e54441f
commit
37b754f073
231
inc/RRule.php
231
inc/RRule.php
@ -31,7 +31,7 @@ class iCalDate {
|
||||
|
||||
/** Fragmented parts */
|
||||
var $_yy;
|
||||
var $_mm;
|
||||
var $_mo;
|
||||
var $_dd;
|
||||
var $_hh;
|
||||
var $_mi;
|
||||
@ -44,10 +44,23 @@ class iCalDate {
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* The constructor takes either a text string formatted as an iCalendar date, or
|
||||
* epoch seconds.
|
||||
* The constructor takes either an iCalendar date, a text string formatted as
|
||||
* an iCalendar date, or epoch seconds.
|
||||
*/
|
||||
function iCalDate( $input ) {
|
||||
if ( gettype($input) == 'object' ) {
|
||||
$this->_text = $input->_text;
|
||||
$this->_epoch = $input->_epoch;
|
||||
$this->_yy = $input->_yy;
|
||||
$this->_mo = $input->_mo;
|
||||
$this->_dd = $input->_dd;
|
||||
$this->_hh = $input->_hh;
|
||||
$this->_mi = $input->_mi;
|
||||
$this->_ss = $input->_ss;
|
||||
$this->_tz = $input->_tz;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_wkst = 1; // Monday
|
||||
if ( preg_match( '/^\d{8}T\d{6}$/', $input ) ) {
|
||||
$this->SetLocalDate($input);
|
||||
@ -210,9 +223,9 @@ class iCalDate {
|
||||
/**
|
||||
* Add some number of months to a date
|
||||
*/
|
||||
function AddMonths( $mm ) {
|
||||
dbg_error_log( "RRule", " Adding %d months to %s", $mm, $this->_text );
|
||||
$this->_mo += $mm;
|
||||
function AddMonths( $mo ) {
|
||||
dbg_error_log( "RRule", " Adding %d months to %s", $mo, $this->_text );
|
||||
$this->_mo += $mo;
|
||||
while ( $this->_mo < 1 ) {
|
||||
$this->_mo += 12;
|
||||
$this->_yy--;
|
||||
@ -233,7 +246,7 @@ class iCalDate {
|
||||
}
|
||||
$this->_EpochFromParts();
|
||||
$this->_TextFromEpoch();
|
||||
dbg_error_log( "RRule", " Added %d months and got %s", $mm, $this->_text );
|
||||
dbg_error_log( "RRule", " Added %d months and got %s", $mo, $this->_text );
|
||||
}
|
||||
|
||||
|
||||
@ -374,8 +387,8 @@ class iCalDate {
|
||||
* @return boolean Whether this date falls within one of those months.
|
||||
*/
|
||||
function TestByMonth( $monthlist ) {
|
||||
dbg_error_log( "RRule", " Testing BYMONTH %s against month %d", (isset($monthlist) ? $monthlist : "no month list"), $this->_mo );
|
||||
if ( !isset($monthlist) ) return true; // If BYMONTH is not specified any month is OK
|
||||
dbg_error_log( "RRule", " Testing BYMONTH %s against month %d", $monthlist, $this->_mo );
|
||||
$months = array_flip(split( ',',$monthlist ));
|
||||
return isset($months[$this->_mo]);
|
||||
}
|
||||
@ -445,12 +458,29 @@ class iCalDate {
|
||||
*/
|
||||
function GreaterThan($lesser) {
|
||||
if ( is_object($lesser) ) {
|
||||
dbg_error_log( "RRule", " Comparing %s with %s", $this->_text, $lesser->_text );
|
||||
return ( $this->_text > $lesser->_text );
|
||||
}
|
||||
dbg_error_log( "RRule", " Comparing %s with %s", $this->_text, $lesser );
|
||||
return ( $this->_text > $lesser ); // These sorts of dates are designed that way...
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if $this is less than the date parameter
|
||||
* @param string $greater The other date, as a local time string
|
||||
* @return boolean True if $this < $greater
|
||||
*/
|
||||
function LessThan($greater) {
|
||||
if ( is_object($greater) ) {
|
||||
dbg_error_log( "RRule", " Comparing %s with %s", $this->_text, $greater->_text );
|
||||
return ( $this->_text < $greater->_text );
|
||||
}
|
||||
dbg_error_log( "RRule", " Comparing %s with %s", $this->_text, $greater );
|
||||
return ( $this->_text < $greater ); // These sorts of dates are designed that way...
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given a MonthDays string like "1MO", "-2WE" return an integer day of the month.
|
||||
*
|
||||
@ -469,7 +499,7 @@ class iCalDate {
|
||||
$dow = $ical_weekdays[$matches[2]];
|
||||
|
||||
$first_matching_day = 1 + ($dow - $dow_first);
|
||||
if ( $first_matching_day < 0 ) $first_matching_day += 7;
|
||||
while ( $first_matching_day < 1 ) $first_matching_day += 7;
|
||||
|
||||
dbg_error_log( "RRule", " Looking at %d for first match on (%s/%s), %d for numeric", $first_matching_day, $matches[1], $matches[2], $numeric );
|
||||
|
||||
@ -664,15 +694,10 @@ class RRule {
|
||||
* follow the iCalendar standard.
|
||||
*/
|
||||
function RRule( $start, $rrule ) {
|
||||
if ( is_object($start) ) {
|
||||
$this->_first = $start;
|
||||
}
|
||||
else {
|
||||
$this->_first = new iCalDate($start);
|
||||
}
|
||||
$this->_first = new iCalDate($start);
|
||||
$this->_finished = false;
|
||||
$this->_started = false;
|
||||
$this->_dates = array( $this->_first );
|
||||
$this->_dates = array();
|
||||
$this->_current = -1;
|
||||
|
||||
$this->_rule = preg_replace( '/\s/m', '', $rrule);
|
||||
@ -711,32 +736,107 @@ class RRule {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
dbg_error_log( "RRule", " WithinScope: Testing for day %d", $day );
|
||||
|
||||
$test = new iCalDate($base);
|
||||
$days_in_month = $test->DaysInMonth();
|
||||
|
||||
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) ) {
|
||||
$ok_days[$day] = $test;
|
||||
$ptr++;
|
||||
}
|
||||
|
||||
if ( isset($this->_part['COUNT']) && $ptr >= $this->_part['COUNT'] ) {
|
||||
$this->_finished = true;
|
||||
return $ok_days;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $ok_days;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is most of the meat of the RRULE processing, where we find the next date.
|
||||
* We maintain an
|
||||
*/
|
||||
function &GetNext( ) {
|
||||
$next = $this->_dates[$this->_current];
|
||||
$this->_current++;
|
||||
|
||||
/**
|
||||
* If we have already found some dates we may just be able to return one of those.
|
||||
*/
|
||||
if ( isset($this->_dates[$this->_current]) ) {
|
||||
return $this->_dates[$this->_current];
|
||||
if ( $this->_finished ) {
|
||||
$next = null;
|
||||
return $next;
|
||||
}
|
||||
|
||||
if ( $this->_current < 0 ) {
|
||||
$next = new iCalDate($this->_first);
|
||||
$this->_current++;
|
||||
}
|
||||
else {
|
||||
if ( isset($this->_part['COUNT']) && $this->_current >= $this->_part['COUNT'] ) // >= since _current is 0-based and COUNT is 1-based
|
||||
$this->_finished = true;
|
||||
if ( $this->_finished ) {
|
||||
$next = null;
|
||||
return $next;
|
||||
$next = new iCalDate($this->_dates[$this->_current]);
|
||||
$this->_current++;
|
||||
|
||||
dbg_error_log( "RRule", " GetNext: Continuing: %s, starting from %s, consider %s, (%d'th)",
|
||||
isset($this->_started) ,
|
||||
(isset($next) ? $next->Render() : "not calculated"),
|
||||
(isset($this->_dates[$this->_current]) ? $this->_dates[$this->_current]->Render():"not calculated") ,
|
||||
$this->_current );
|
||||
/**
|
||||
* If we have already found some dates we may just be able to return one of those.
|
||||
*/
|
||||
if ( isset($this->_dates[$this->_current]) ) {
|
||||
dbg_error_log( "RRule", " GetNext: Returning %s, (%d'th)", $this->_dates[$this->_current]->Render(), $this->_current );
|
||||
return $this->_dates[$this->_current];
|
||||
}
|
||||
else {
|
||||
if ( isset($this->_part['COUNT']) && $this->_current >= $this->_part['COUNT'] ) // >= since _current is 0-based and COUNT is 1-based
|
||||
$this->_finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
$days = array();
|
||||
if ( isset($this->_part['WKST']) ) $next->SetWeekStart($this->_part['WKST']);
|
||||
if ( $this->_part['FREQ'] == "MONTHLY" ) {
|
||||
dbg_error_log( "RRule", " Calculating more dates for MONTHLY rule" );
|
||||
$limit = 100;
|
||||
do {
|
||||
$limit--;
|
||||
@ -764,29 +864,23 @@ class RRule {
|
||||
$days = $next->ApplyBySetpos($this->_part['BYSETPOS'], $days);
|
||||
}
|
||||
|
||||
if ( ! $next->GreaterThan($this->_first) ) {
|
||||
dbg_error_log( "RRule", " Removing dates less than or equal to %s", $this->_first->Render() );
|
||||
foreach( $days AS $k => $v ) {
|
||||
if ( $k <= $this->_first->_dd ) {
|
||||
unset($days[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$days = $this->WithinScope( $next, $days);
|
||||
dbg_error_log( "RRule", " Found %d days so far for MONTHLY rule", count($days) );
|
||||
}
|
||||
while( $limit && count($days) < 1 );
|
||||
while( $limit && count($days) < 1 && ! $this->_finished );
|
||||
|
||||
}
|
||||
else if ( $this->_part['FREQ'] == "DAILY" ) {
|
||||
dbg_error_log( "RRule", " Calculating more dates for DAILY rule" );
|
||||
$limit = 100;
|
||||
do {
|
||||
$limit--;
|
||||
if ( $this->_started ) {
|
||||
$next->AddDays($this->_part['INTERVAL']);
|
||||
}
|
||||
else {
|
||||
$this->_started = true;
|
||||
}
|
||||
if ( $this->_started ) {
|
||||
$next->AddDays($this->_part['INTERVAL']);
|
||||
}
|
||||
else {
|
||||
$this->_started = true;
|
||||
}
|
||||
|
||||
if ( isset($this->_part['BYDAY']) ) {
|
||||
$days = $next->GetWeekByDay($this->_part['BYDAY']);
|
||||
@ -798,56 +892,23 @@ class RRule {
|
||||
$days = $next->ApplyBySetpos($this->_part['BYSETPOS'], $days);
|
||||
}
|
||||
|
||||
if ( ! $next->GreaterThan($this->_first) ) {
|
||||
dbg_error_log( "RRule", " Removing dates less than or equal to %s", $this->_first->Render() );
|
||||
foreach( $days AS $day => $v ) {
|
||||
if ( $day <= $this->_first->_dd ) {
|
||||
unset($days[$day]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$days = $this->WithinScope( $next, $days);
|
||||
dbg_error_log( "RRule", " Found %d days so far for DAILY rule", count($days) );
|
||||
}
|
||||
while( $limit && count($days) < 1 );
|
||||
while( $limit && count($days) < 1 && ! $this->_finished );
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
$next_month = false;
|
||||
$prev_month = false;
|
||||
$days_in_month = $next->DaysInMonth();
|
||||
foreach( $days AS $day => $v ) {
|
||||
if ( $day > $days_in_month ) {
|
||||
$next_month = true;
|
||||
$next->SetMonthDay($days_in_month);
|
||||
$next->AddDays(1);
|
||||
}
|
||||
else if ( $day < 1 ) {
|
||||
$prev_month = true;
|
||||
$next->SetMonthDay(1);
|
||||
$next->AddDays(-1);
|
||||
$days_in_month = $next->DaysInMonth();
|
||||
}
|
||||
|
||||
if ( $next_month ) {
|
||||
$day -= $days_in_month;
|
||||
}
|
||||
else if ( $prev_month ) {
|
||||
$day += $days_in_month;
|
||||
}
|
||||
|
||||
$next->SetMonthDay($day);
|
||||
if ( isset($this->_part['UNTIL']) && $next->GreaterThan($this->_part['UNTIL']) ) {
|
||||
$this->_finished = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->_dates[$this->_current + $i] = $next;
|
||||
$i++;
|
||||
$ptr = $this->_current;
|
||||
foreach( $days AS $k => $v ) {
|
||||
$this->_dates[$ptr++] = $v;
|
||||
}
|
||||
|
||||
if ( isset($this->_dates[$this->_current]) ) {
|
||||
dbg_error_log( "RRule", " GetNext: Returning %s, (%d'th)", $this->_dates[$this->_current]->Render(), $this->_current );
|
||||
return $this->_dates[$this->_current];
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "RRule", " GetNext: Returning null date" );
|
||||
$next = null;
|
||||
return $next;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user