The biggest issue is when having interval of 1 (or more) full months. For example: adding one month to the date of 2013-01-31 you'll end up with the date 2013-03-03 when you expect to be 2013-02-28.
Here is the function I wrote for solving this problem. You can enhance this to support year or hours or even ice ages :P
<?php /** * Function calculateNextDueDate - given a start date and an interval type and value * calculate next date in the future. * * @param DateTime $startDate * @param string $intervalType * @param integer $intervalValue * * @return DateTime */ function calculateNextDueDate($startDate, $intervalType, $intervalValue) { $currentDate = new DateTime(); $currentDay = $currentDate->format('d'); $currentDate->sub(new DateInterval('P' . ($currentDay - 1) . 'D')); $processDate = clone $startDate; $dayOfTheMonth = $processDate->format('d'); $periodString = 'P' . (int)$intervalValue; switch ($intervalType) { case 'month': $periodString .= 'M'; if (28 < $dayOfTheMonth) { $modifyInterval = new DateInterval('P' . ($dayOfTheMonth - 28) . 'D'); $processDate->sub($modifyInterval); } break; case 'day': $periodString .= 'D'; break; } $interval = new DateInterval($periodString); while ($currentDate->getTimestamp() >= $processDate->getTimestamp()) { $processDate = $processDate->add($interval); } if ($processDate->format('d') < $currentDay) { $processDate = $processDate->add($interval); } if ('month' == $intervalType && 28 < $dayOfTheMonth) { $lastDateOfMonth = $processDate->format('t'); if ($dayOfTheMonth > $lastDateOfMonth) { $daysToAdd = $lastDateOfMonth - 28; } else { $daysToAdd = $dayOfTheMonth - 28; } $processDate->add(new DateInterval('P' . $daysToAdd . 'D')); } return $processDate; }
No comments:
Post a Comment