mirror of
https://gitlab.com/davical-project/davical.git
synced 2026-05-26 02:44:29 +00:00
An RRule library that seems to cover most of the basic and some of the not
so basic use of RRULE in iCalendar. And a few test cases.
This commit is contained in:
parent
5a72ac12b5
commit
530409877f
106
inc/RRule.php
106
inc/RRule.php
@ -408,9 +408,8 @@ class iCalDate {
|
|||||||
function GetMonthByMonthDay($bymonthday) {
|
function GetMonthByMonthDay($bymonthday) {
|
||||||
dbg_error_log( "RRule", " Applying BYMONTHDAY %s to month", $bymonthday );
|
dbg_error_log( "RRule", " Applying BYMONTHDAY %s to month", $bymonthday );
|
||||||
$days_in_month = $this->DaysInMonth();
|
$days_in_month = $this->DaysInMonth();
|
||||||
$dayrules = split(',',$byday);
|
$dayrules = split(',',$bymonthday);
|
||||||
$set = array();
|
$set = array();
|
||||||
$first_dow = (date('w',$this->_epoch) - $this->_dd + 36) % 7;
|
|
||||||
foreach( $dayrules AS $k => $v ) {
|
foreach( $dayrules AS $k => $v ) {
|
||||||
$v = intval($v);
|
$v = intval($v);
|
||||||
if ( $v > 0 && $v <= $days_in_month ) $set[$v] = 1;
|
if ( $v > 0 && $v <= $days_in_month ) $set[$v] = 1;
|
||||||
@ -418,12 +417,36 @@ class iCalDate {
|
|||||||
return $set;
|
return $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies any BYDAY to the week to return a set of days
|
||||||
|
* @param string $byday The BYDAY rule
|
||||||
|
* @return array An array of the day numbers for the week which meet the rule.
|
||||||
|
*/
|
||||||
|
function GetWeekByDay($byday) {
|
||||||
|
global $ical_weekdays;
|
||||||
|
dbg_error_log( "RRule", " Applying BYDAY %s to week", $byday );
|
||||||
|
$days = split(',',$byday);
|
||||||
|
$dow = date('w',$this->_epoch);
|
||||||
|
foreach( $days AS $k => $v ) {
|
||||||
|
$daynum = $ical_weekdays[$v];
|
||||||
|
$dd = $this->_dd - $dow + $daynum;
|
||||||
|
if ( $daynum < $this->_wkst ) $dd += 7;
|
||||||
|
$set[$dd] = 1;
|
||||||
|
}
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if $this is greater than the date parameter
|
* Test if $this is greater than the date parameter
|
||||||
* @param string $lesser The other date, as a local time string
|
* @param string $lesser The other date, as a local time string
|
||||||
* @return boolean True if $this > $lesser
|
* @return boolean True if $this > $lesser
|
||||||
*/
|
*/
|
||||||
function GreaterThan($lesser) {
|
function GreaterThan($lesser) {
|
||||||
|
if ( is_object($lesser) ) {
|
||||||
|
return ( $this->_text > $lesser->_text );
|
||||||
|
}
|
||||||
return ( $this->_text > $lesser ); // These sorts of dates are designed that way...
|
return ( $this->_text > $lesser ); // These sorts of dates are designed that way...
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,6 +494,32 @@ class iCalDate {
|
|||||||
return $set;
|
return $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given set position descriptions like '1', '3', '11', '-3' or '-1' and a set,
|
||||||
|
* return the subset matching the list of set positions.
|
||||||
|
*
|
||||||
|
* @param string $bysplist The list of set positions.
|
||||||
|
* @param string $set The set of days that we will apply the positions to.
|
||||||
|
*
|
||||||
|
* @return array The subset which matches.
|
||||||
|
*/
|
||||||
|
function &ApplyBySetPos($bysplist, &$set) {
|
||||||
|
dbg_error_log( "RRule", " Applying '%s' to set of %d days", $bysplist, count($set) );
|
||||||
|
$subset = array();
|
||||||
|
$max = count($set);
|
||||||
|
$positions = split( '[^0-9-]', $bysplist );
|
||||||
|
foreach( $positions AS $k => $v ) {
|
||||||
|
if ( $v < 0 ) {
|
||||||
|
$v += $max;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$v--;
|
||||||
|
}
|
||||||
|
$subset[] = $set[$v];
|
||||||
|
}
|
||||||
|
return $subset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -710,6 +759,15 @@ class RRule {
|
|||||||
$days = $next->ApplyBySetpos($this->_part['BYSETPOS'], $days);
|
$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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
while( $limit && count($days) < 1 );
|
while( $limit && count($days) < 1 );
|
||||||
|
|
||||||
@ -724,19 +782,59 @@ class RRule {
|
|||||||
else {
|
else {
|
||||||
$this->_started = true;
|
$this->_started = true;
|
||||||
}
|
}
|
||||||
$days[$next->_dd] = 1;
|
|
||||||
|
if ( isset($this->_part['BYDAY']) ) {
|
||||||
|
$days = $next->GetWeekByDay($this->_part['BYDAY']);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$days[$next->_dd] = 1;
|
||||||
|
|
||||||
|
if ( isset($this->_part['BYSETPOS']) ) {
|
||||||
|
$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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while( $limit && count($days) < 1 );
|
while( $limit && count($days) < 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
$i = 0;
|
$i = 0;
|
||||||
|
$next_month = false;
|
||||||
|
$prev_month = false;
|
||||||
|
$days_in_month = $next->DaysInMonth();
|
||||||
foreach( $days AS $day => $v ) {
|
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);
|
$next->SetMonthDay($day);
|
||||||
if ( isset($this->_part['UNTIL']) && $next->GreaterThan($this->_part['UNTIL']) ) {
|
if ( isset($this->_part['UNTIL']) && $next->GreaterThan($this->_part['UNTIL']) ) {
|
||||||
$this->_finished = true;
|
$this->_finished = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/** FIXME should check this is greater than the first date here too */
|
|
||||||
$this->_dates[$this->_current + $i] = $next;
|
$this->_dates[$this->_current + $i] = $next;
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,8 +13,10 @@ $tests = array(
|
|||||||
"20061103T073000" => "RRULE:FREQ=DAILY;COUNT=7"
|
"20061103T073000" => "RRULE:FREQ=DAILY;COUNT=7"
|
||||||
, "20061102T100000" => "RRULE:FREQ=WEEKLY;COUNT=26;INTERVAL=1;BYDAY=TH"
|
, "20061102T100000" => "RRULE:FREQ=WEEKLY;COUNT=26;INTERVAL=1;BYDAY=TH"
|
||||||
, "20061103T160000" => "RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=20071222T235900"
|
, "20061103T160000" => "RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=20071222T235900"
|
||||||
|
, "20061101T160000" => "RRULE:FREQ=WEEKLY;COUNT=15;INTERVAL=1;BYDAY=MO,WE,FR"
|
||||||
, "20061104T073000" => "RRULE:FREQ=MONTHLY"
|
, "20061104T073000" => "RRULE:FREQ=MONTHLY"
|
||||||
, "20061117T073000" => "RRULE:FREQ=MONTHLY;BYDAY=1MO,2WE,3FR,-1SU"
|
, "20061117T073000" => "RRULE:FREQ=MONTHLY;BYDAY=1MO,2WE,3FR,-1SU"
|
||||||
|
, "20061107T113000" => "RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1"
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach( $tests AS $start => $rrule ) {
|
foreach( $tests AS $start => $rrule ) {
|
||||||
@ -29,7 +31,7 @@ foreach( $tests AS $start => $rrule ) {
|
|||||||
echo " " . $date->Render();
|
echo " " . $date->Render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while( isset($date) && $i++ < 50 );
|
while( isset($date) && $i++ < 30 );
|
||||||
|
|
||||||
echo "\n\n\n";
|
echo "\n\n\n";
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user