Many fixes to the RRule handling both for correctness and PHP5.

This commit is contained in:
Andrew McMillan 2007-03-07 12:39:38 +13:00
parent 37b754f073
commit bc15ec03e6
3 changed files with 69 additions and 43 deletions

View File

@ -236,12 +236,10 @@ class iCalDate {
}
if ( ($this->_dd > 28 && $this->_mo == 2) || $this->_dd > 30 ) {
// Ensure the day of month is still reasonable
// Ensure the day of month is still reasonable and coerce to last day of month if needed
$dim = $this->DaysInMonth();
if ( $this->_dd > $dim ) {
// We don't need to check for month > 12, since _dd can't be greater than 31 if it was previously valid
$this->_mo++;
$this->_dd -= $dim;
$this->_dd = $dim;
}
}
$this->_EpochFromParts();
@ -407,9 +405,10 @@ class iCalDate {
foreach( $dayrules AS $k => $v ) {
$days = $this->MonthDays($first_dow,$days_in_month,$v);
foreach( $days AS $k2 => $v2 ) {
$set[$v2] = 1;
$set[$v2] = $v2;
}
}
asort( $set, SORT_NUMERIC );
return $set;
}
@ -425,8 +424,9 @@ class iCalDate {
$set = array();
foreach( $dayrules AS $k => $v ) {
$v = intval($v);
if ( $v > 0 && $v <= $days_in_month ) $set[$v] = 1;
if ( $v > 0 && $v <= $days_in_month ) $set[$v] = $v;
}
asort( $set, SORT_NUMERIC );
return $set;
}
@ -445,8 +445,9 @@ class iCalDate {
$daynum = $ical_weekdays[$v];
$dd = $this->_dd - $dow + $daynum;
if ( $daynum < $this->_wkst ) $dd += 7;
$set[$dd] = 1;
$set[$dd] = $dd;
}
asort( $set, SORT_NUMERIC );
return $set;
}
@ -458,10 +459,10 @@ class iCalDate {
*/
function GreaterThan($lesser) {
if ( is_object($lesser) ) {
dbg_error_log( "RRule", " Comparing %s with %s", $this->_text, $lesser->_text );
// 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 );
// dbg_error_log( "RRule", " Comparing %s with %s", $this->_text, $lesser );
return ( $this->_text > $lesser ); // These sorts of dates are designed that way...
}
@ -473,10 +474,10 @@ class iCalDate {
*/
function LessThan($greater) {
if ( is_object($greater) ) {
dbg_error_log( "RRule", " Comparing %s with %s", $this->_text, $greater->_text );
// 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 );
// dbg_error_log( "RRule", " Comparing %s with %s", $this->_text, $greater );
return ( $this->_text < $greater ); // These sorts of dates are designed that way...
}
@ -492,7 +493,7 @@ class iCalDate {
*/
function &MonthDays($dow_first, $days_in_month, $dayspec) {
global $ical_weekdays;
dbg_error_log( "RRule", " Getting days for '%s'. %d days starting on a %d", $dayspec, $days_in_month, $dow_first );
dbg_error_log( "RRule", "MonthDays: Getting days for '%s'. %d days starting on a %d", $dayspec, $days_in_month, $dow_first );
$set = array();
preg_match( '/([0-9-]*)(MO|TU|WE|TH|FR|SA|SU)/', $dayspec, $matches);
$numeric = intval($matches[1]);
@ -501,7 +502,7 @@ class iCalDate {
$first_matching_day = 1 + ($dow - $dow_first);
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 );
dbg_error_log( "RRule", " MonthDays: Looking at %d for first match on (%s/%s), %d for numeric", $first_matching_day, $matches[1], $matches[2], $numeric );
while( $first_matching_day <= $days_in_month ) {
$set[] = $first_matching_day;
@ -516,10 +517,17 @@ class iCalDate {
$numeric--;
}
$answer = $set[$numeric];
$set = array( $answer );
$set = array( $answer => $answer );
}
else {
$answers = $set;
$set = array();
foreach( $answers AS $k => $v ) {
$set[$v] = $v;
}
}
dbg_log_array( "RRule", 'MonthDays', $set, false );
// dbg_log_array( "RRule", 'MonthDays', $set, false );
return $set;
}
@ -534,9 +542,10 @@ class iCalDate {
*
* @return array The subset which matches.
*/
function &ApplyBySetPos($bysplist, &$set) {
dbg_error_log( "RRule", " Applying '%s' to set of %d days", $bysplist, count($set) );
function &ApplyBySetPos($bysplist, $set) {
dbg_error_log( "RRule", " ApplyBySetPos: Applying set position '%s' to set of %d days", $bysplist, count($set) );
$subset = array();
sort( $set, SORT_NUMERIC );
$max = count($set);
$positions = split( '[^0-9-]', $bysplist );
foreach( $positions AS $k => $v ) {
@ -546,7 +555,7 @@ class iCalDate {
else {
$v--;
}
$subset[] = $set[$v];
$subset[$set[$v]] = $set[$v];
}
return $subset;
}
@ -747,13 +756,13 @@ class RRule {
$ptr = $this->_current;
dbg_error_log( "RRule", " WithinScope: Processing list of %d days relative to %s", count($relative_days), $base->Render() );
// 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();
// 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);
@ -778,9 +787,10 @@ class RRule {
return $ok_days;
}
if ( $this->_current >= 0 && $test->LessThan($this->_dates[$this->_current]) ) continue;
// 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++;
}
@ -815,11 +825,14 @@ class RRule {
$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.
*/
@ -836,7 +849,7 @@ class RRule {
$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" );
dbg_error_log( "RRule", " GetNext: Calculating more dates for MONTHLY rule" );
$limit = 100;
do {
$limit--;
@ -858,20 +871,20 @@ class RRule {
$days = $next->GetMonthByMonthDay($this->_part['BYMONTHDAY']);
}
else
$days[$next->_dd] = 1;
$days[$next->_dd] = $next->_dd;
if ( isset($this->_part['BYSETPOS']) ) {
$days = $next->ApplyBySetpos($this->_part['BYSETPOS'], $days);
}
$days = $this->WithinScope( $next, $days);
dbg_error_log( "RRule", " Found %d days so far for MONTHLY rule", count($days) );
}
while( $limit && count($days) < 1 && ! $this->_finished );
dbg_error_log( "RRule", " GetNext: Found %d days for MONTHLY rule", count($days) );
}
else if ( $this->_part['FREQ'] == "DAILY" ) {
dbg_error_log( "RRule", " Calculating more dates for DAILY rule" );
dbg_error_log( "RRule", " GetNext: Calculating more dates for DAILY rule" );
$limit = 100;
do {
$limit--;
@ -886,16 +899,17 @@ class RRule {
$days = $next->GetWeekByDay($this->_part['BYDAY']);
}
else
$days[$next->_dd] = 1;
$days[$next->_dd] = $next->_dd;
if ( isset($this->_part['BYSETPOS']) ) {
$days = $next->ApplyBySetpos($this->_part['BYSETPOS'], $days);
}
$days = $this->WithinScope( $next, $days);
dbg_error_log( "RRule", " Found %d days so far for DAILY rule", count($days) );
}
while( $limit && count($days) < 1 && ! $this->_finished );
dbg_error_log( "RRule", " GetNext: Found %d days for DAILY rule", count($days) );
}
$ptr = $this->_current;

View File

@ -16,6 +16,7 @@ $tests = array(
, "20061101T160000" => "RRULE:FREQ=WEEKLY;COUNT=15;INTERVAL=1;BYDAY=MO,WE,FR"
, "20061104T073000" => "RRULE:FREQ=MONTHLY"
, "20061117T073000" => "RRULE:FREQ=MONTHLY;BYDAY=1MO,2WE,3FR,-1SU"
, "20061107T103000" => "RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR"
, "20061107T113000" => "RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1"
);

View File

@ -1,6 +1,6 @@
HTTP/1.1 200 OK
Date: Dow, 01 Jan 2000 00:00:00 GMT
Content-Length: 4314
Content-Length: 5020
Content-Type: text/plain; charset=UTF-8
Testing the RRule Library
@ -38,8 +38,7 @@ Testing the RRule Library
2006-11-01 16:00:00 2006-11-03 16:00:00 2006-11-06 16:00:00 2006-11-08 16:00:00
2006-11-10 16:00:00 2006-11-13 16:00:00 2006-11-15 16:00:00 2006-11-17 16:00:00
2006-11-20 16:00:00 2006-11-22 16:00:00 2006-11-24 16:00:00 2006-11-27 16:00:00
2006-10-30 16:00:00 2006-10-31 16:00:00 2006-11-06 16:00:00 2006-11-08 16:00:00
2006-11-10 16:00:00
2006-11-29 16:00:00 2006-12-01 16:00:00 2006-12-04 16:00:00
20061104T073000 - RRULE:FREQ=MONTHLY
@ -58,23 +57,35 @@ Testing the RRule Library
2006-11-17 07:30:00 2006-11-26 07:30:00 2006-12-04 07:30:00 2006-12-13 07:30:00
2006-12-15 07:30:00 2006-12-31 07:30:00 2007-01-01 07:30:00 2007-01-10 07:30:00
2007-01-19 07:30:00 2007-01-28 07:30:00 2007-02-05 07:30:00 2007-02-07 07:30:00
2007-02-16 07:30:00 2007-02-25 07:30:00 2007-03-05 07:30:00 2007-03-07 07:30:00
2007-01-19 07:30:00 2007-01-28 07:30:00 2007-02-05 07:30:00 2007-02-14 07:30:00
2007-02-16 07:30:00 2007-02-25 07:30:00 2007-03-05 07:30:00 2007-03-14 07:30:00
2007-03-16 07:30:00 2007-03-25 07:30:00 2007-04-02 07:30:00 2007-04-11 07:30:00
2007-04-20 07:30:00 2007-04-29 07:30:00 2007-04-30 07:30:00 2007-04-30 07:30:00
2007-04-30 07:30:00 2007-04-30 07:30:00 2007-04-30 07:30:00 2007-04-30 07:30:00
2007-04-30 07:30:00 2007-04-30 07:30:00 2007-04-30 07:30:00
2007-04-20 07:30:00 2007-04-29 07:30:00 2007-05-07 07:30:00 2007-05-09 07:30:00
2007-05-18 07:30:00 2007-05-27 07:30:00 2007-06-04 07:30:00 2007-06-13 07:30:00
2007-06-15 07:30:00 2007-06-24 07:30:00 2007-07-02 07:30:00
20061107T103000 - RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR
2006-11-07 10:30:00 2006-11-08 10:30:00 2006-11-09 10:30:00 2006-11-10 10:30:00
2006-11-13 10:30:00 2006-11-14 10:30:00 2006-11-15 10:30:00 2006-11-16 10:30:00
2006-11-17 10:30:00 2006-11-20 10:30:00 2006-11-21 10:30:00 2006-11-22 10:30:00
2006-11-23 10:30:00 2006-11-24 10:30:00 2006-11-27 10:30:00 2006-11-28 10:30:00
2006-11-29 10:30:00 2006-11-30 10:30:00 2006-12-01 10:30:00 2006-12-04 10:30:00
2006-12-05 10:30:00 2006-12-06 10:30:00 2006-12-07 10:30:00 2006-12-08 10:30:00
2006-12-11 10:30:00 2006-12-12 10:30:00 2006-12-13 10:30:00 2006-12-14 10:30:00
2006-12-15 10:30:00 2006-12-18 10:30:00 2006-12-19 10:30:00
20061107T113000 - RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1
2006-11-07 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00
2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00
2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00
2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00
2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00
2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00
2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00
2006-11-30 11:30:00 2006-11-30 11:30:00 2006-11-30 11:30:00
2006-11-30 11:30:00 2006-12-29 11:30:00 2007-01-31 11:30:00 2007-02-28 11:30:00
2007-03-30 11:30:00 2007-04-30 11:30:00 2007-05-31 11:30:00 2007-06-29 11:30:00
2007-07-31 11:30:00 2007-08-31 11:30:00 2007-09-28 11:30:00 2007-10-31 11:30:00
2007-11-30 11:30:00 2007-12-31 11:30:00 2008-01-31 11:30:00 2008-02-29 11:30:00
2008-03-31 11:30:00 2008-04-30 11:30:00 2008-05-30 11:30:00 2008-06-30 11:30:00
2008-07-31 11:30:00 2008-08-29 11:30:00 2008-09-30 11:30:00 2008-10-31 11:30:00
2008-11-28 11:30:00 2008-12-31 11:30:00 2009-01-30 11:30:00 2009-02-27 11:30:00
2009-03-31 11:30:00 2009-04-30 11:30:00 2009-05-29 11:30:00