Version: 1.0
Type: Function
Category: Calendars/Dates
License: GNU General Public License
Description: This function lets you check whether an date event should recur on a specified date. This is handy for calendar, billing and reminder applications.
/** * 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