1

I'd like to calculate next billing date of Recurly plan in PHP. There are 2 types of billing cycle: yearly | monthly. I tried to use DateTime and DateInterval classes, but didn't get expected results.

<?php
$referenceTime = new \DateTime('2016-01-31');
$oneMonthLater = $referenceTime->modify('+1 month');
var_dump($oneMonthLater);
// public 'date' => string '2016-03-02 00:00:00.000000'

Adding one month to the 31st of Januray gives me the second of March and not the 29th (or 28th) of February as I would expect.

The same for the 31st of August:

<?php
$referenceTime = new \DateTime('2016-08-31');
$oneMonthLater = $referenceTime->modify('+1 month');
var_dump($oneMonthLater);
// public 'date' => string '2016-10-01 00:00:00.000000'

If yearly, I expect Feb 29, 2016 + 1 year => Feb 28, 2017

Thanks.

Paul Z.
  • 855
  • 1
  • 10
  • 27
  • Show us what you have done so far... It will be easier for us to answer. – d.coder Dec 06 '16 at 11:40
  • $next_bill_date = new DateTime(); if ($plan_interval_unit == 'year') { $interval_spec = 'P'.$plan['plan_interval_length'].'Y'; } else if ($plan_interval_unit == 'month') { $interval_spec = 'P'.$plan['plan_interval_length'].'M'; } $next_bill_date->add(new DateInterval($interval_spec)); – Paul Z. Dec 06 '16 at 11:41
  • Add it in your question please. Hard to read/understand here... :( – d.coder Dec 06 '16 at 11:42

5 Answers5

3

Try this, if date > 28 use last day of next month else use +1 month

$get_date = strtotime("31-01-2016");
$dt = explode("-",$get_date);
$dt = $dt[0];
var_dump(($dt > 28) ? date("d-m-Y", strtotime("31-01-2016 last day of next month")) : date("d-m-Y", strtotime("31-01-2016 +1 month")));

DEMO

Dave
  • 3,073
  • 7
  • 20
  • 33
1

You can call modify with PHP's DateTime object to calculate the next date relative to the current date. The following code shows how you would do it with your specific situation.

$next_bill_date = new DateTime();
switch($plan_interval_unit) {
    case "year":
        $next_bill_date->modify("last day of next month");
        break;

    case "month":
        $next_bill_date->modify("last day of this month next year");
        break;
}
Ryan Tse
  • 1,559
  • 11
  • 15
0

May be something like that:

if (date('d') !== date('d', strtotime('+1 month'))
    date ('Y-m-d H:i:s', strtotime('last day of next month'));

if (date('d') !== date('d', strtotime('+1 year'))
    date ('Y-m-d H:i:s', strtotime('last day of this month next year'));
vuryss
  • 1,270
  • 8
  • 16
0

You can use PHP inbuilt strtotime() function

// One month from today
$date = date('Y-m-d', strtotime('+1 month'));

// One month from a specific date
$date = date('Y-m-d', strtotime('+1 month', strtotime('2016-12-06')));
Hiren Makwana
  • 1,976
  • 2
  • 13
  • 28
0
function get_next_billing_date($now, $type, $format = 'Y-m-d')
{
    $date = new DateTime($now);

    $y = $date->format("Y");
    $m = $date->format("m");
    $d = $date->format("d");

    if ($type == 'year') {
        $y++;
        if ($m == 2 && $d == 29) {
            $d = 28;
        }
    } else if ($type == 'month') {
        if ($m == 12) {
            $y++;
            $m = 1;
        } else {
            $m++;
        }

        $first_date = sprintf("%04d-%02d-01", $y, $m);
        $last_day_of_next_month = date('t', strtotime($first_date));

        if ($d > $last_day_of_next_month) {
            $d = $last_day_of_next_month;
        }
    } else {
        // not supported
        return false;
    }

    $date->setDate($y, $m, $d);

    return $date->format($format);
}
Paul Z.
  • 855
  • 1
  • 10
  • 27