'int', )); } public function getNextEventEpoch($last_epoch, $is_reschedule) { $start_epoch = $this->getProperty('start'); if (!$last_epoch) { $last_epoch = $start_epoch; } // Constructing DateTime objects like this implies UTC, so we don't need // to set that explicitly. $start = new DateTime('@'.$start_epoch); $last = new DateTime('@'.$last_epoch); $year = (int)$last->format('Y'); $month = (int)$last->format('n'); // Note that we're getting the day of the month from the start date, not // from the last event date. This lets us schedule on March 31 after moving // the date back to Feb 28. $day = (int)$start->format('j'); // We trigger at the same time of day as the original event. Generally, // this means that you should get invoiced at a reasonable local time in // most cases, unless you subscribed at 1AM or something. $hms = $start->format('G:i:s'); // Increment the month by 1. $month = $month + 1; // If we ran off the end of the calendar, set the month back to January // and increment the year by 1. if ($month > 12) { $month = 1; $year = $year + 1; } // Now, move the day backward until it falls in the correct month. If we // pass an invalid date like "2014-2-31", it will internally be parsed // as though we had passed "2014-3-3". while (true) { $next = new DateTime("{$year}-{$month}-{$day} {$hms} UTC"); if ($next->format('n') == $month) { // The month didn't get corrected forward, so we're all set. break; } else { // The month did get corrected forward, so back off a day. $day--; } } return (int)$next->format('U'); } }