Recurring Date Checker

Submitted by:David Villa

Date added:16 November, 2013

Category:PHP

This function lets you check whether an date event should recur on a specified date. This is handy for calendar, billing and reminder applications.

Tags: date checker

Code Snippet:

/**
* Returns whether or not a an item with the specified information should recur / repeat.
*
* Example 1:
* You have an event, such as a birthday that repeats each year and would like to know
* if today is the day it should repeat on.
*
* //$bday = '2008-10-29', $today = '2008-10-29'
* recursOn($today, $bday, 'year', 1, null, true) //returns true
*
* Example 2:
* You have a collection of invoices which may need to be reproduced on a
* recurring basis, such as a monthly subscription. The following snippet
* will look through a collection of invoices which recur every month
* on the Xth day of the month and insert any invoices that should recur
* today into an array (shouldRecur) for additional processing.
*
* $shouldRecur = array();
* foreach ($invoices as $invoice) {
* if (recursOn(date('Y-m-d'), $invoice->date, 'month', 1, null, true)) {
* $shouldRecur[] = $invoice;
* }
* }
*
* @param $testDate a string date in the format YYYY-MM-DD that indicates the date that should be tested for recurrence
* @param $originalDate a string date in the format YYYY-MM-DD that indicates the original date of the event
* @param $measure the measure of the recurrence. Acceptable values are 'day', 'week', 'month', and 'year'
* @param $frequency the number of days/weeks/months/years for the recurrence frequency, i.e., every 1 day, every 2 months, etc.
* @param $endDate the date on which the recurrence should end
* @param $byDate true if the recurrence should take place by date, e.g., the 15th (for month measure) or
* March 12th (for year measure), or by its day, such as the second Tuesday of the month (for month measure)
* or 345th day of the year (for year measure). This field does not matter for day or week measure.
*/
public function recursOn($testDate, $originalDate, $measure, $frequency, $endDate = null, $byDate = true)
{
if (!in_array($measure, array('day', 'week', 'month', 'year'))) {
throw new Exception('recursOn: Unsupported measure: '.$measure);
}

if ($frequency <= 0) {
throw new Exception('recursOn: frequency must be greater than 0');
}

$testFormat = '^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}( [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}){0,1}$';
if (!ereg($testFormat, $testDate)) {
throw new Exception('recursOn: testDate must be in the format YYYY-MM-DD, not '.$testDate);
}

if (!ereg($testFormat, $originalDate)) {
throw new Exception('recursOn: originalDate must be in the format YYYY-MM-DD, not '.$originalDate);
}

if ($endDate && !ereg($testFormat, $endDate)) {
throw new Exception('recursOn: endDate must be in the format YYYY-MM-DD, not '.$endDate);
}

$stestDate = strtotime($testDate);
$soriginalDate = strtotime($originalDate);
$sendDate = strtotime($endDate);

// if we are past the recurrence end date for this item
if ($endDate && $endDate != '0000-00-00 00:00:00' && $sendDate < $stestDate) {
return false;
}

// if the event should not start yet
if ($stestDate < $soriginalDate) {
return false;
}

switch ($measure) {
case 'day':
//if the number of days that has passed is an even number based on the frequency
return (date('z', $stestDate) - date('z', $soriginalDate)) % $frequency == 0;
case 'week':
//check to see if this is the correct week
if ((date('W', $stestDate) - date('W', $soriginalDate)) % $frequency == 0) {
// are we on the correct day?
return date('w', $stestDate) == date('w', $soriginalDate);
}
break;
case 'month':
//check to see if this is the correct month
if ((date('n', $stestDate) - date('n', $soriginalDate)) % $frequency == 0) {
// are we on the correct day?
if ($byDate) {
// it is the Xth of the month
return date('j', $stestDate) == date('j', $soriginalDate);
}

// it is something like the second Tuesday, etc., so we get the number of
// the week within the month, then check that along with the day of the week
$oweekno = ceil((double)date('j', $soriginalDate) / 7);
$sweekno = ceil((double)date('j', $stestDate) / 7);

return $oweekno == $sweekno && date('w', $soriginalDate) == date('w', $stestDate);
}
break;
case 'year':
// check to see if this is the correct month
if ((date('Y', $stestDate) - date('Y', $soriginalDate)) % $frequency == 0) {
// check to see if this is the correct date
if ($byDate) {
return date('m-d', $soriginalDate) == date('m-d', $stestDate);
}

// is it the same day of the year?
return date('z', $soriginalDate) == date('z', $stestDate);
}
break;
}

return false;
} //end recursOn
 
 

Comments