# Calculating recurring months

Hi I have been working for 2 days on this function but still puzzled as to how to make it work properly (accurately). Basically I have a church event that recurs every 1month. It may recur every 2, 3 or 4 month depending on user input, but for now I just keep it simple for a month.

I want to display the event consistently throughout the calendar monthly, I got it to work on 24th July, 24th August but on September, it lands on 22nd of Sept and I can’t seems to figure out why. Hope anyone could shed some light here, thanks in advanced.

``````
// Event start time from the database
\$startTimestamp = strtotime( '2011-07-24' );

// The current selected date user is viewing from the calendar
// Example: 2011-07-01 (2011-08-01 works, then 2011-09-01 became 22nd)
\$selected = '2011-07-01';

// Returns the exact number of days in the selected month
// This is a function I got from PHP.net strtotime from a user's comment. It basically returns the correct number of days in any specific months with leap in considerations.
\$numberDays = days_left_in_month( \$selected );

// Get the correct number of days and convert to seconds
// *1 is for 1 month interval
\$recursEvery = (86400*\$numberDays*1);

// find the first occurrence in the selected month
\$firstOccurance = strtotime( \$selected );
\$startDate = new DateTime( date( 'Y-m-d', \$firstOccurance ) );

while( 0 != ((\$startDate->getTimestamp( )-\$startTimestamp) % \$recursEvery)) {
\$startDate->modify('+1 day');
}
echo \$startDate->format('Y-m-d' );

// This is a function I got from PHP.net strtotime from a user's comment. It basically returns the correct number of days in any specific months with leap in considerations.
function days_left_in_month(\$isoDate) {
\$date = explode('-', \$isoDate);
\$date[1]++;
if (\$date[1] == '13') {
\$date[0]++;
\$date[1] = '01';
}
\$date[2] = '01';
\$isoDateNextMonth = implode('-', \$date);
return ceil((strtotime(\$isoDateNextMonth) - strtotime(\$isoDate)) / 86400);
}

``````

You can just copy paste and run this directly, then change the \$selected variable for testing:

\$selected = ‘2011-07-01’; // outputs 24th
\$selected = ‘2011-08-01’; // outputs 24th
\$selected = ‘2011-09-01’; // outputs 22nd

Maybe i’m just being silly here, but why not use the add function of the datetime object?

``````
function recurrs(\$from,\$to,\$monthleap) {
\$curdate = \$from;
\$out = array();
\$curdt = new DateTime( \$curdate );
\$interval = new DateInterval('P'.\$monthleap.'M');
while(\$curdt->format('Y-m-d') <= \$to) { //Note: Works based on String Comparison of YYYY-MM-DD format!
\$out[] = \$curdt->format('Y-m-d' );
}
return \$out;
}
``````

Thanks Starlion, can you explain what is \$monthleap so as I can test it out?

\$monthleap = ‘how many months to skip before recurring’ (1 = every month, 2 = every other month, etc.)

Or for that matter (As i look at it now and see that it will throw problems with 1 month periods), just treat the thing as a zero padded integer.

``````function recurrs(\$from,\$to,\$monthleap) {
\$curdate = \$from;
\$out = array();

while(\$curdate <= \$to) {
\$out[] = \$curdate;
\$curdate = explode('-',\$curdate);
\$curdate[1] += \$monthleap;
if(\$curdate[1] >= 13) {
\$curdate[1] = \$curdate[1] % 12;
\$curdate[0]++;
}
\$curdate = implode('-',\$curdate);
}
return \$out;
}

``````

Did I use your function the correct way as I’m getting 0 result?

``````
// Event start time from the database
\$startTimestamp = '2011-07-24';

// The current selected date user is viewing from the calendar
\$selected = '2011-07-01';

var_dump( recurrs(\$startTimestamp, \$selected,1));

``````

I don’t think it works Starlion lol, but thanks nonetheless…

That’s not the way the function was designed. The second parameter is the End date (stop recurring at…)

You cant run a while loop without an end condition.

there was one line i got wrong though.

``````    \$curdate[1] = str_pad(\$curdate[1],2,"0");
``````

becomes

``````    \$curdate[1] = str_pad(\$curdate[1],2,"0",STR_PAD_LEFT);
``````

So:

``````
function recurrs(\$from,\$to,\$monthleap) {
\$curdate = \$from;
\$out = array();

while(\$curdate <= \$to) {
\$out[] = \$curdate;
\$curdate = explode('-',\$curdate);
\$curdate[1] += \$monthleap;
if(\$curdate[1] >= 13) {
\$curdate[1] = \$curdate[1] % 12;
\$curdate[0]++;
}
\$curdate = implode('-',\$curdate);
}
return \$out;
}
// Event start time from the database
\$startTimestamp = '2011-07-24';

// The current selected date user is viewing from the calendar
\$selected = '2015-07-01';

print_r( recurrs(\$startTimestamp, \$selected,1));

``````

Output:

``````
Array ( [0] => 2011-07-24 [1] => 2011-08-24 [2] => 2011-09-24 [3] => 2011-10-24 [4] => 2011-11-24 [5] => 2011-12-24 [6] => 2012-01-24 [7] => 2012-02-24 [8] => 2012-03-24 [9] => 2012-04-24 [10] => 2012-05-24 [11] => 2012-06-24 [12] => 2012-07-24 [13] => 2012-08-24 [14] => 2012-09-24 [15] => 2012-10-24 [16] => 2012-11-24 [17] => 2012-12-24 [18] => 2013-01-24 [19] => 2013-02-24 [20] => 2013-03-24 [21] => 2013-04-24 [22] => 2013-05-24 [23] => 2013-06-24 [24] => 2013-07-24 [25] => 2013-08-24 [26] => 2013-09-24 [27] => 2013-10-24 [28] => 2013-11-24 [29] => 2013-12-24 [30] => 2014-01-24 [31] => 2014-02-24 [32] => 2014-03-24 [33] => 2014-04-24 [34] => 2014-05-24 [35] => 2014-06-24 [36] => 2014-07-24 [37] => 2014-08-24 [38] => 2014-09-24 [39] => 2014-10-24 [40] => 2014-11-24 [41] => 2014-12-24 [42] => 2015-01-24 [43] => 2015-02-24 [44] => 2015-03-24 [45] => 2015-04-24 [46] => 2015-05-24 [47] => 2015-06-24 )
``````

Would I be right in guessing you want this event to take place on the n’th Sunday in each month? Or do you want it to really happen on the 22nd of each month?