RecurrenceIterator
in package
implements
Iterator
Iterator to calculate all occurrences of a recurring event.
Table of Contents
Interfaces
- Iterator
Constants
- DEFAULT_COUNTS = ['YEARLY' => 10, 'MONTHLY' => 12, 'WEEKLY' => 52, 'DAILY' => 365, 'HOURLY' => 720, 'MINUTELY' => 1440, 'SECONDLY' => 3600]
- TYPE_ABSOLUTE = 0
- TYPE_ALLDAY = 2
- TYPE_FLOATING = 1
- WEEKDAY_NAMES = ['MO' => 'Monday', 'TU' => 'Tuesday', 'WE' => 'Wednesday', 'TH' => 'Thursday', 'FR' => 'Friday', 'SA' => 'Saturday', 'SU' => 'Sunday']
Properties
- $by : array<string|int, mixed>
- $dtstart : DateTimeInterface
- $exdates : array<string|int, mixed>
- $frequency_interval : DateInterval
- $key : int
- $limit_after : DateTimeImmutable
- $limit_before : DateTimeImmutable
- $max_occurrences : int|float
- $occurrences : array<string|int, mixed>
- $rdates : array<string|int, mixed>
- $record_format : string
- $rrule : RRule
- $rrule_occurrences : array<string|int, mixed>
- $type : int
- $view_end : DateTimeImmutable
- $view_start : DateTimeImmutable
Methods
- __construct() : mixed
- Constructor.
- add() : void
- Adds an arbitrary date to the recurrence set.
- calculateWeekNum() : int
- Calculates the week number of a date according to RFC 5545.
- current() : DateTimeInterface|false
- Returns a \DateTimeInterface object for the currently selected element in the event's recurrence set.
- dateOccurs() : bool
- Checks whether the given date/time occurs in the recurrence set.
- end() : void
- Moves the iterator key to the end.
- getDtStart() : DateTimeInterface
- Returns a copy of $this->dtstart.
- getExDates() : array<string|int, mixed>
- Returns a copy of $this->exdates.
- getFrequencyInterval() : DateInterval
- Returns a copy of $this->frequency_interval.
- getNext() : DateTimeInterface|false
- Moves the iterator key one step forward, and then returns a DateTimeInterface object for the newly selected element in the event's recurrence set.
- getPrev() : DateTimeInterface|false
- Moves the iterator key one step backward, and then returns a DateTimeInterface object for the newly selected element in the event's recurrence set.
- getRDates() : array<string|int, mixed>
- Returns a copy of $this->rdates.
- getRRule() : RRule
- Returns a copy of the recurrence rule.
- getRRuleOccurrences() : array<string|int, mixed>
- Returns occurrences generated by the RRule only.
- key() : int
- Get the current value of the iterator key.
- next() : void
- Moves the iterator key one step forward.
- prev() : void
- Moves the iterator key one step backward.
- remove() : void
- Removes a date from the recurrence set.
- rewind() : void
- Moves the iterator key back to the beginning.
- search() : int|false
- Finds the iterator key that corresponds to the requested value.
- setKey() : int
- Moves the iterator key to a specific position.
- valid() : bool
- Checks whether the current value of the iterator key is valid.
- calculate() : void
- Calculates occurrences based on the recurrence rule.
- expand() : Generator<string|int, DateTimeImmutable>
- Finds additional occurrences based on any BYxxx rule parts in the RRule.
- expandMonthByDay() : Generator<string|int, DateTimeImmutable>
- Used when expanding an occurrence that is part of a monthly recurrence set that has a byday rule, or part of a yearly recurrence set that has both a bymonth rule and a byday rule.
- expandYearByDay() : Generator<string|int, DateTimeImmutable>
- Used when expanding an occurrence that is part of a yearly recurrence set that has a byday rule but not a bymonth rule.
- jumpToVisible() : void
- If possible, move $current ahead in order to skip values before $this->view_start.
- limit() : bool
- Checks whether a calculated occurrence should be included based on BYxxx rule parts in the RRule.
- limitBySetPos() : void
- Applies BYSETPOS limitation to the reccurrence set.
- nextInterval() : void
- Move $current ahead to the next interval.
- record() : bool
- Adds an occurrence to $this->occurrences.
- setFrequencyInterval() : void
- Sets the value of $this->frequency_interval.
- sortWeekdays() : array<string|int, mixed>
- Sorts an array of weekday abbreviations so that $this->rrule->wkst is always the first item.
Constants
DEFAULT_COUNTS
public
array<string|int, mixed>
DEFAULT_COUNTS
= ['YEARLY' => 10, 'MONTHLY' => 12, 'WEEKLY' => 52, 'DAILY' => 365, 'HOURLY' => 720, 'MINUTELY' => 1440, 'SECONDLY' => 3600]
Used to calculate a default value for $this->view_end.
These are only used when the RRule repeats forever and no value was specified for the constructor's $view parameter.
Keys are possible values of $this->rrule->freq. Values are the number of times to add $this->frequency_interval to $this->view_start in order to calculate $this->view_end.
These defaults are entirely arbitrary choices by the developer. ;)
TYPE_ABSOLUTE
public
int
TYPE_ABSOLUTE
= 0
Indicates that the event has a date, time, and time zone.
For example, an absolute event on '2023-10-26 14:00:00 Europe/Paris' will occur on Oct 26, 2023, at 2:00 PM for a user in Paris, France, but at 8:00 AM for a user in Toronto, Canada, and at 11:00 PM for a user in Sydney, Australia.
TYPE_ALLDAY
public
int
TYPE_ALLDAY
= 2
Indicates that the event has a specific date, but no time or time zone.
For example, an all day event on '2023-10-26' will occur on Oct 26, 2023, starting at midnight in whatever time zone the viewer happens to be in, and ending on the following midnight in that time zone.
TYPE_FLOATING
public
int
TYPE_FLOATING
= 1
Indicates that the event has specific date and time, but no time zone.
For example, a floating event on '2023-10-26 14:00:00' will occur on Oct 26, 2023, at 2:00 PM in whatever time zone the viewer happens to currently be in.
WEEKDAY_NAMES
public
array<string|int, mixed>
WEEKDAY_NAMES
= ['MO' => 'Monday', 'TU' => 'Tuesday', 'WE' => 'Wednesday', 'TH' => 'Thursday', 'FR' => 'Friday', 'SA' => 'Saturday', 'SU' => 'Sunday']
Maps RFC 5545 weekday abbreviations to full weekday names.
The order of the elements matters. Do not change it.
Properties
$by
private
array<string|int, mixed>
$by
= ['bysecond' => ['fmt' => 's', 'type' => 'int', 'is_expansion' => false], 'byminute' => ['fmt' => 'i', 'type' => 'int', 'is_expansion' => false], 'byhour' => ['fmt' => 'H', 'type' => 'int', 'is_expansion' => false], 'byday' => ['fmt' => 'D', 'type' => 'string', 'adjust' => '$current_value = strtoupper(substr($current_value, 0, 2));', 'is_expansion' => false], 'bymonthday' => ['fmt' => 'j', 'type' => 'int', 'is_expansion' => false], 'byyearday' => ['fmt' => 'z', 'type' => 'int', 'adjust' => '$current_value++;', 'is_expansion' => false], 'byweekno' => ['fmt' => 'W', 'type' => 'int', 'is_expansion' => true], 'bymonth' => ['fmt' => 'm', 'type' => 'int', 'is_expansion' => false]]
Info about how to process the various BYxxx rule parts (except BYSETPOS).
As RFC 5545 says:
"BYxxx rule parts modify the recurrence in some manner. BYxxx rule parts for a period of time that is the same or greater than the frequency generally reduce or limit the number of occurrences of the recurrence generated. [...] BYxxx rule parts for a period of time less than the frequency generally increase or expand the number of occurrences of the recurrence."
For more info on these rule parts and how they modify the recurrence, see RFC 5545, §3.3.10.
Note: the order of the elements in this array matters. Do not change it.
$dtstart
private
DateTimeInterface
$dtstart
Date of the first occurrence of the event.
$exdates
private
array<string|int, mixed>
$exdates
= []
Timestamps of dates to exclude from the recurrence set.
$frequency_interval
private
DateInterval
$frequency_interval
How far to jump ahead for each main iteration of the recurrence rule.
Derived from $this->rrule->freq and $this->rrule->interval.
$key
private
int
$key
= 0
Iterator key. Points to the current element of $this->occurrences when iterating over an instance of this class.
$limit_after
private
DateTimeImmutable
$limit_after
Occurrences after this date will not be calculated.
This value is typically one frequency interval after $this->view_end.
$limit_before
private
DateTimeImmutable
$limit_before
Occurrences before this date will not be calculated.
This value is typically one frequency interval before $this->view_start.
$max_occurrences
private
int|float
$max_occurrences
Used for sanity checks.
Value may change based on $this->rrule->freq and/or $this->rrule->count.
$occurrences
private
array<string|int, mixed>
$occurrences
= []
Date string records of all valid occurrences.
$rdates
private
array<string|int, mixed>
$rdates
= []
Timestamps of dates to add to the recurrence set. These are dates besides the ones generated from the RRule.
$record_format
private
string
$record_format
= 'Ymd\THis\Z'
\DateTime format to use for the records in $this->occurrences.
$rrule
private
RRule
$rrule
The recurrence rule for this event.
$rrule_occurrences
private
array<string|int, mixed>
$rrule_occurrences
= []
Date string records of the initial recurrence set generated from the RRule before any RDates or ExDates are applied.
$type
private
int
$type
The type of event (normal, floating, or all day), as indicated by one of this class's TYPE_* constants.
$view_end
private
DateTimeImmutable
$view_end
Occurrences after this date will be skipped when returning results.
$view_start
private
DateTimeImmutable
$view_start
Occurrences before this date will be skipped when returning results.
Methods
__construct()
Constructor.
public
__construct(RRule $rrule, DateTimeInterface $dtstart[, DateInterval|null $view = null ][, DateTimeInterface|null $view_start = null ][, int|null $type = null ][, array<string|int, mixed>|null $rdates = [] ][, array<string|int, mixed>|null $exdates = [] ]) : mixed
Parameters
- $rrule : RRule
-
The recurrence rule for this event.
- $dtstart : DateTimeInterface
-
Date of the event's first occurrence.
- $view : DateInterval|null = null
-
Length of the period for which dates will be shown. For example, use \DateInterval('P1M') to show one month's worth of occurrences, \DateInterval('P1W') to show one week's worth, etc. If null, will be determined automatically.
- $view_start : DateTimeInterface|null = null
-
Lower limit for dates to be shown. Iterating over the object will never return values before this date. If null, will be set to $this->dtstart.
- $type : int|null = null
-
One of this class's TYPE_* constants, or null to set it automatically based on the UNTIL value of the RRule. If this is null and the RRule's UNTIL value is null, default is TYPE_ABSOLUTE.
- $rdates : array<string|int, mixed>|null = []
-
Arbitrary dates to add to the recurrence set. Elements must be arrays containing an instance of \DateTimeInterface and an optional \DateInterval. Used to make exceptions to the general recurrence rule.
- $exdates : array<string|int, mixed>|null = []
-
Dates to exclude from the recurrence set. Elements must be instances of \DateTimeInterface. Used to make exceptions to the general recurrence rule.
add()
Adds an arbitrary date to the recurrence set.
public
add(DateTimeInterface $date[, DateInterval|null $duration = null ]) : void
Used for making exceptions to the general recurrence rule. Note that calling this method always rewinds the iterator key.
Parameters
- $date : DateTimeInterface
-
The date to add.
- $duration : DateInterval|null = null
-
Optional duration for this occurrence. Only necessary if the duration for this occurrence differs from the usual duration of the event.
calculateWeekNum()
Calculates the week number of a date according to RFC 5545.
public
static calculateWeekNum(DateTimeInterface $current, string $wkst) : int
Parameters
- $current : DateTimeInterface
- $wkst : string
Return values
intcurrent()
Returns a \DateTimeInterface object for the currently selected element in the event's recurrence set.
public
current() : DateTimeInterface|false
If $this->type is self::TYPE_FLOATING or self::TYPE_ALLDAY, the returned object will be a mutable \DateTime instance so that its time zone can be changed to the viewing user's current time zone.
Otherwise, the returned object will a \DateTimeImmutable instance.
Return values
DateTimeInterface|false —The date of the occurrence, or false on error.
dateOccurs()
Checks whether the given date/time occurs in the recurrence set.
public
dateOccurs(DateTimeInterface $date) : bool
Parameters
- $date : DateTimeInterface
-
A date.
Return values
bool —Whether the date occurs in the recurrence set.
end()
Moves the iterator key to the end.
public
end() : void
getDtStart()
Returns a copy of $this->dtstart.
public
getDtStart() : DateTimeInterface
Return values
DateTimeInterfacegetExDates()
Returns a copy of $this->exdates.
public
getExDates() : array<string|int, mixed>
Return values
array<string|int, mixed>getFrequencyInterval()
Returns a copy of $this->frequency_interval.
public
getFrequencyInterval() : DateInterval
Return values
DateIntervalgetNext()
Moves the iterator key one step forward, and then returns a DateTimeInterface object for the newly selected element in the event's recurrence set.
public
getNext() : DateTimeInterface|false
Return values
DateTimeInterface|false —The next occurrence, or false if there are no more occurrences.
getPrev()
Moves the iterator key one step backward, and then returns a DateTimeInterface object for the newly selected element in the event's recurrence set.
public
getPrev() : DateTimeInterface|false
Return values
DateTimeInterface|false —The previous occurrence, or false if there is no previous occurrence.
getRDates()
Returns a copy of $this->rdates.
public
getRDates() : array<string|int, mixed>
Return values
array<string|int, mixed>getRRule()
Returns a copy of the recurrence rule.
public
getRRule() : RRule
Return values
RRulegetRRuleOccurrences()
Returns occurrences generated by the RRule only.
public
getRRuleOccurrences() : array<string|int, mixed>
Return values
array<string|int, mixed>key()
Get the current value of the iterator key.
public
key() : int
Return values
int —The current value of the iterator key.
next()
Moves the iterator key one step forward.
public
next() : void
prev()
Moves the iterator key one step backward.
public
prev() : void
remove()
Removes a date from the recurrence set.
public
remove(DateTimeInterface $date) : void
Used for making exceptions to the general recurrence rule. Note that calling this method always rewinds the iterator key.
Parameters
- $date : DateTimeInterface
-
The date to remove.
rewind()
Moves the iterator key back to the beginning.
public
rewind() : void
search()
Finds the iterator key that corresponds to the requested value.
public
search(string $needle) : int|false
Parameters
- $needle : string
-
The value to search for.
Return values
int|false —The key for the requested value, or false on error.
setKey()
Moves the iterator key to a specific position.
public
setKey(int $key) : int
If the requested key is invalid, will go to the closest valid one.
Parameters
- $key : int
Return values
int —The new value of the iterator key.
valid()
Checks whether the current value of the iterator key is valid.
public
valid() : bool
Return values
bool —Whether the current value of the iterator key is valid.
calculate()
Calculates occurrences based on the recurrence rule.
private
calculate() : void
expand()
Finds additional occurrences based on any BYxxx rule parts in the RRule.
private
expand(DateTime $current[, string $break_after = null ]) : Generator<string|int, DateTimeImmutable>
Expansions are occurrences that happen inside one iteration of the RRule's stated frequency. For example, if the frequency is set to HOURLY, that normally means that the event recurs on minute 0 of every hour (or whatever minute was set in DTSTART). But if the RRule's BYMINUTE property is set to '0,30', then the occurrences are expanded so that the event recurs at minute 0 and minute 30 of every hour.
Parameters
- $current : DateTime
-
An occurrence of the event to expand.
- $break_after : string = null
-
Name of a $this->by element. Used during recursive calls to this method.
Return values
Generator<string|int, DateTimeImmutable>expandMonthByDay()
Used when expanding an occurrence that is part of a monthly recurrence set that has a byday rule, or part of a yearly recurrence set that has both a bymonth rule and a byday rule.
private
expandMonthByDay(DateTime $current, array<string|int, mixed> $expansion_values, string $current_value) : Generator<string|int, DateTimeImmutable>
Parameters
- $current : DateTime
-
An occurrence of the event to expand.
- $expansion_values : array<string|int, mixed>
-
Values from the byday rule.
- $current_value : string
Return values
Generator<string|int, DateTimeImmutable>expandYearByDay()
Used when expanding an occurrence that is part of a yearly recurrence set that has a byday rule but not a bymonth rule.
private
expandYearByDay(DateTime $current, array<string|int, mixed> $expansion_values, string $current_value) : Generator<string|int, DateTimeImmutable>
Parameters
- $current : DateTime
-
An occurrence of the event to expand.
- $expansion_values : array<string|int, mixed>
-
Values from the byday rule.
- $current_value : string
Return values
Generator<string|int, DateTimeImmutable>jumpToVisible()
If possible, move $current ahead in order to skip values before $this->view_start.
private
jumpToVisible(DateTime &$current) : void
Parameters
- $current : DateTime
limit()
Checks whether a calculated occurrence should be included based on BYxxx rule parts in the RRule.
private
limit(DateTime $current) : bool
Limitations cause occurrences that would normally occur according the RRule's stated frequency to be skipped. For example, if the frequency is set to HOURLY, that normally means that the event recurs on minute 0 of every hour (or whatever minute was set in DTSTART) of every day. But if the BYDAY rule part is set to 'TU,TH', then occurrences are limited so that the event recurs only at every hour during Tuesdays and Thursdays. Occurrences that happen on any other day of the week are skipped.
Parameters
- $current : DateTime
-
A occurrence whose value we want to check.
Return values
bool —Whether the occurrence is allowed.
limitBySetPos()
Applies BYSETPOS limitation to the reccurrence set.
private
limitBySetPos() : void
nextInterval()
Move $current ahead to the next interval.
private
nextInterval(DateTime &$current) : void
Handles months of varying lengths according to RFC 5545's rules.
Parameters
- $current : DateTime
record()
Adds an occurrence to $this->occurrences.
private
record(DateTimeInterface $occurrence) : bool
Parameters
- $occurrence : DateTimeInterface
Return values
bool —True if the occurrence is a new addition; false if it is a duplicate or out of bounds.
setFrequencyInterval()
Sets the value of $this->frequency_interval.
private
setFrequencyInterval() : void
sortWeekdays()
Sorts an array of weekday abbreviations so that $this->rrule->wkst is always the first item.
private
sortWeekdays(array<string|int, mixed> $weekdays) : array<string|int, mixed>
Parameters
- $weekdays : array<string|int, mixed>
-
An array of weekday abbreviations.
Return values
array<string|int, mixed> —Sorted version of $weekdays.