Recurrence
, (*1)
This library allows you to create recurring DateTimes based on intervals, e.g every last wednesday of the month for the
next 2 years., (*2)
It comes with some core Intervals, but it's built to allow you to create and use your own for your own project
requirements., (*3)
It acts much like the DatePeriod PHP iterator in that it accepts a start date, end date and an interval object, however
it gives us some more functionality also., (*4)
Contents
- Requirements
- Installation
- Usage
- Contributing
- License
The only requirement currently is a minimum PHP version of 5.6., (*5)
CURRENTLY HACK / HHVM IS NOT SUPPORTED, (*6)
Composer is the recommended installation method:, (*7)
composer require jrbarnard/date-interval-iterator
However you can also download this repo, unzip it and include it in your project., (*8)
The package comprises of three class types, these can be used separately or all together., (*9)
Occurrences
The occurrences class is a container to store DateTimes. It's basically just a wrapper around an array, but allows us
a bit more flexibility in the future if we want to deal with a collection of DateTimes / the stored occurrences from
the iterator., (*10)
$occurrences = new Occurrences();
// Add an occurrence in
$occurrences->push(new DateTime);
// $popped will be the last added occurrence
$popped = $occurrences->pop();
$occurrences->push(new DateTime);
// Can get an occurrence by index
$occurrence = $occurrences->getOccurrence(0);
Occurrences also implements the ArrayAccess interface meaning we can use the occurrences object just like an array:, (*11)
$occurrences = new Occurrences();
// Same as push
$occurrences[] = new DateTime();
// $occurrence will be the 0th index DateTime object
$occurrence = $occurrences[0];
Currently it doesn't have any internal validation, fancier methods for filtering etc. These are things we may add in
the future., (*12)
Intervals
Intervals are the classes that define how we get the next occurrence within the iterator. They mirror the functionality
of PHP's core DateIntervals where their purpose is to take a datetime and return back a datetime after applying their
interval to it., (*13)
E.g Datetime of 2012-01-01, interval of 1 day, we would expect to get back a datetime of 2012-01-02., (*14)
Intervals can be as simple or as complex as you want, we provide a few, however you can make and use your own, they
just must implement the IntervalInterface., (*15)
E.g:, (*16)
use JRBarnard\Reccurrence\Intervals\IntervalInterface;
class ExampleInterval implements IntervalInterface
{
/**
* Method that finds the next occurrence of the interval from current
*
* @param DateTime $current
* @param $direction
*
* @return DateTime
*/
public function findNextOccurrence(DateTime $current, $direction = self::FORWARDS)
{
$interval = new \DateInterval('PT12M');
$cloned = clone $current;
if ($direction === self::BACKWARDS) {
return $cloned->sub($interval);
} else {
return $cloned->add($interval);
}
}
}
The above example would apply the interval of 12 minutes to the date time, you can see this very basic interval is at
it's core utilising a PHP DateInterval. This works well for simple Intervals, however may not be suitable for more
complex ones., (*17)
Intervals also accept a direction, forwards or backwards, you can use the constants defined within the
IntervalInterface., (*18)
The intervals that come with the package as standard are:, (*19)
- DailyInterval - Accepts an integer number of days and will add / sub that number of days from the passed in DateTime
new DailyInterval(12);
(new DailyInterval())->setNumberOfDays(12);
- HourlyInterval - Accepts a numeric (can be float) number of hours and will add / sub that number of minutes from
the passed in DateTime - E.g if you pass 3.5, that will equate to 210 minutes. If you pass 1.472826 that will equate to
88 minutes.
new HourlyInterval(1.5);
(new HourlyInterval())->setNumberOfHours(1.5);
- WeeklyInterval - Accepts days of the week and the weekly occurrence, so you can do intervals such as: every Tuesday
and Wednesday of every 3rd week.
// Basic usage via constructor
new WeeklyInterval([WeeklyInterval::WEDNESDAY, WeeklyInterval::TUESDAY], 3);
// Standard setters
$interval = new WeeklyInterval();
$interval->setDays([WeeklyInterval::TUESDAY, WeeklyInterval::WEDNESDAY]);
$interval->setWeeks(3);
// Magic setters
(new WeeklyInterval())->everyTuesday()->andEveryWednesday()->ofEvery3rdWeek();
- MonthlyInterval - Accepts days of the week and the monthly occurrence, so you can do intervals such as: the last
Wednesday and Thursday of every other month.
// Basic usage via constructor
new MonthlyInterval(MonthlyInterval::LAST, [MonthlyInterval::WEDNESDAY, MonthlyInterval::THURSDAY], 2);
// Standard setters
$interval = new MonthlyInterval();
$interval->setDays([MonthlyInterval::WEDNESDAY, MonthlyInterval::THURSDAY]);
$interval->setFrequency(MonthlyInterval::LAST);
$interval->setMonths(2);
// Magic setters
(new MonthlyInterval())->every(MonthlyInterval::LAST, [MonthlyInterval::WEDNESDAY, MonthlyInterval::THURSDAY])->ofEveryMonth(2);
(new MonthlyInterval())->everyLast()->wednesday()->andThursday()->ofEvery2ndMonth();
Iterator
The Iterator is the class you can use to apply your intervals over a set DateTime / Occurrence range., (*20)
For example it lets you do things like:
- Get an occurrence every hour and a half until next week:, (*21)
$start = new DateTime(); // Now
$end = (new DateTime())->add(new DateInterval('P1W'));
$interval = new HourlyInterval(1.5);
$iterator = new DateIntervalIterator($start, $interval, $end);
foreach($iterator as $occurrence) {
// $occurrence will be a DateTime instance of every hour and half till next week
}
- Get the next 50 occurrences of every 2nd Wednesday and Thursdays:
$start = new DateTime(); // Now
$end = 50;
$interval = new WeeklyInterval([WeeklyInterval::WEDNESDAY, WeeklyInterval::THURSDAY], 2);
$iterator = new DateIntervalIterator($start, $interval, $end);
foreach($iterator as $occurrence) {
// $occurrence will be a DateTime instance of every 2nd Wednesday and Thursday up to 50 occurrences.
}
This allows us to calculate dates for things like recurring events easily., (*22)
As mentioned above, you can create your own intervals, so you should be able to create an interval / iterator to fit
your own needs., (*23)
Iterators also have a few extra features:
* They are countable, if all you want is how many times an occurrence will occur you can do:, (*24)
$iterator->count();
// Or:
count($iterator);
- You can specify to skip certain DateTimes: E.g if you want an occurrence every hour and half, but not one of the
occurrences for whatever reason, you can:
$iterator->skip(new DateTime('2012-02-02 12:30:00'));
// You can also check if the iterator should skip a particular datetime:
$iterator->shouldSkip('2012-02-02 12:30:00');
// Will return true
- You can set when the iterator should end to a DateTime or a number of occurrences, for example you may want to get an
occurrence every hour before 5:30pm on a certain day, you can and it will stop iterating when the next occurrence it
would get goes beyond this limit. Or if you prefer to set a number of occurrence limit, e.g every hour for the next 10
hours, you can by just passing an int:
$iterator->setEndAfter(10);
$iterator->setEndAfter('2016-12-12 17:30:00');
// You can also use a getter:
$iterator->getEndAfter();
- You can set a hard upper limit on number of occurrences to prevent the iterator accidentally iterating too much:
// It defaults to 100 when you instantiate the iterator
$iterator->setMaxOccurrences(20);
// If you now try and set an end after over the max it will throw an exception
// If you set an end after to a date, it wil; stop iterating either when it reaches that date or the max occurrences,
// whichever occurs first.
- You can set a direction for the iterator, so you can get the say every last Wednesday of every month from now, back 2
years:
$iterator->setDirection(IntervalInterface::BACKWARDS);
- You can get the occurrences object from the iterator, it will internally run the iterator to ensure it's populated
before returning:
$iterator->getOccurrences();
// Will return an instance of Occurrences
Please look at the contributing file, (*25)
MIT License, (*26)