Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP. How to get a bimonthly recurring event?

Tags:

php

I'm trying many approaches but then I get stuck half way.

Let's say order was created today. I need to display when the next recurring order will happen. So I have order created June 13, 2012. Then I have set the schedule to bimonthly recurring order, every 1st of month. How to calculate when the next recurring order will happen? The answer is August 1st.

If someone can outline an approach it would be very useful, it doesn't have to be code. This is what I have so far...

    // first, get starting date
    $start_date_month = date('m', strtotime($start_date));

    // get this year
    $this_year = date('Y');

    // if this month is december, next month is january
    $this_month = date('m', $timestamp_month);
    if($this_month == 12){
      $next_month = 1;
    // if this month is not december add 1 to get next month
    }else{
      $next_month = $this_month + 1;
    }

    // get array of months where recurring orders will happen
    $months = array();
    for ($i=1; $i<=6; $i++) {
      $add_month = $start_date_month+(2*$i); // 2, 4, 6, 8, 10, 12
      if($add_month == 13){$add_month = 1;$year = $this_year+1;}
      elseif($add_month == 14){$add_month = 2;$year = $this_year+1;}
      elseif($add_month == 15){$add_month = 3;$year = $this_year+1;}
      elseif($add_month == 16){$add_month = 4;$year = $this_year+1;}
      elseif($add_month == 17){$add_month = 5;$year = $this_year+1;}
      elseif($add_month == 18){$add_month = 6;$year = $this_year+1;}
      elseif($add_month == 19){$add_month = 7;$year = $this_year+1;}
      elseif($add_month == 20){$add_month = 8;$year = $this_year+1;}
      else{$year = $this_year;}
      echo $what_day.'-'.$add_month.'-'.$year.'<br />';
      $months[] = $add_month;
    }

    echo '<pre>';
    print_r($months);
    echo '</pre>';

I don't want to simply find what's the date in two months from now. Let's say order created June 1. Next recurring order is August 1. Then let's say now, today is September 1st, but next recurring order is October 1st. See my dilemma?

like image 983
leonel Avatar asked Jun 13 '12 19:06

leonel


2 Answers

Just take the current month, so since it's June, we get 6. 6 mod 2 == 0. Next month is July, we get 7. 7 mod 2 == 1.

So just check if current month % 2 == (first month % 2).

Then just check if it's the 1st of the month.

In PHP modulus is defined with the percentage symbol.

$month = date('n');
$createdMonth = 6;
if($month % 2 == $createdMonth % 2){
    // stuff
}
like image 89
Marcus Recck Avatar answered Sep 22 '22 00:09

Marcus Recck


You might find the library called When useful for this (I'm the author).

Here is code which will get you the next 2 recurring monthly dates (from todays date):

include 'When.php';

$r = new When();
$r->recur(new DateTime(), 'monthly')
  ->count(2)
  ->interval(2) // every other month
  ->bymonthday(array(1));

while($result = $r->next())
{
    echo $result->format('c') . '<br />';
}

// output
// 2012-08-01T13:33:33-04:00
// 2012-10-01T13:33:33-04:00

Taking this a step further, you likely only want to find the 2 first business days:

include 'When.php';

$r = new When();
$r->recur(new DateTime(), 'monthly')
  ->count(2)
  ->interval(2)                                 // every other month
  ->byday(array('MO', 'TU', 'WE', 'TH', 'FR'))  // week days only
  ->bymonthday(array(1, 2, 3))                  // the first weekday will fall on one of these days
  ->bysetpos(array(1));                         // only return one per month

while($result = $r->next())
{
    echo $result->format('c') . '<br />';
}

// output
// 2012-08-01T13:33:33-04:00
// 2012-10-01T13:33:33-04:00

Also note, the code is currently under a rewrite -- it works well but it is a little confusing and not well documented.

like image 27
tplaner Avatar answered Sep 22 '22 00:09

tplaner