Link to home
Start Free TrialLog in
Avatar of sasnaktiv
sasnaktivFlag for United States of America

asked on

PHP Number of months between 2 dates

Hi Guys,
I know this is probably very simple, but I can't seem to find a solution that's right for me.

I'm getting one date from the db as "2011-11-21" and placing that value in the variable "$LastPaymentDueDate"

I'm also creating a future date such as "2012-04-01" and placing that value in the variable "$NextPaymentDueDate"

I don't care about partial months because everyone is supposed to pay up on the first day of every month. I just want a count to tell me how many months a particular payment is overdue by.

Can you help?
Thanks,
Sas
Avatar of David
David
Flag of United States of America image

I'll assume you will have no problem parsing into variables

LAPSEDMONTHS = (FUTUREYEAR - LASTPAYMENTYEAR) * 12 + FUTUREMONTH - LASTPAYMENTMONTH.

Just convert everything into months.   (If number is <= 0, then they are current)
Avatar of sasnaktiv

ASKER

Thanks.
How do I determine from my variables "FUTUREYEAR" and "LASTPAYMENTYEAR"?

And shall I assume "FUTUREMONTH" and "LASTPAYMENTMONTH" would follow the same logic?
Have a look at this article.  The term month is ambiguous because months are not consistent in the elapsed time,  like days or weeks.  While you read that I will try to find a solution that works consistently.
https://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/A_201-Handling-date-and-time-in-PHP-and-MySQL.html
Sorry, Sas - small family emergency.  I cannot work this out now.  Look into mktime() and you will find the best answer.  If you're still unsure tomorrow, please post whatever you have tried and I will get back to you.   Best regards, ~Ray
Thanks Ray,
I hope your family emergency isn't anything serious.

I checked out your link. It's quite impressive. I notice that it is gathering dates a different way than I am. I already have both dates formatted as YYYY-mm-dd. So I don't know how to apply your demos.

Take care,
Sas
Check this out:

<?php
// it was a warm winter day...
$dateB = new DateTime('2012-01-31'); 
print $dateB->format('Y-m-d')."<br/>";
// 3 months later... it's not 31!
$dateB->add(date_interval_create_from_date_string('3 months'));
print $dateB->format('Y-m-d')."<br/>";
?>

Open in new window


You have a whole bunch of methods in the DateTime object.
Just skim thru the corresponding PHP manual pages and you'll get to what you want pretty fast.
SOLUTION
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for the attention designatedinitializer
I ran your code exactly as you posted it and I get the following error.
What can be done to resolve this error?
Thanks.
SAS

2012-01-31
Fatal error: Call to undefined method DateTime::add() in /home/content/p/h/a/pharmacallmobi/html/NEXTSEATING.COM/CONTENT/Nxt_manager/admin/RAY.php on line 8

<?php 
error_reporting(E_ALL);

// it was a warm winter day...
$dateB = new DateTime('2012-01-31'); 
print $dateB->format('Y-m-d')."<br/>";
// 3 months later... it's not 31!
$dateB->add(date_interval_create_from_date_string('3 months'));
print $dateB->format('Y-m-d')."<br/>";
?>

Open in new window

Hi Ray,
Thanks for the help. I hope your family emergency was not serious.
Of course I made some changes to your code in order to get it to work with my db. I'm getting some odd results though, and I hope you can straighten me out.

Below is what is being returned:
FROM 2012-03-09 TO 2012-03-31 THERE ARE 0 MONTHS -- THIS IS OBVIOUSLY CORRECT
FROM 2012-03-09 TO 2012-05-01 THERE ARE 1 MONTHS  -- THE MONTH COUNT SEEMS CORRECT BUT THIS SHOULD BE 2012-04-01   IT ACTUALLY RETURNS 2012-05-01. WHY???
FROM December 2011 TO March 2012 THERE ARE 0 MONTHS
FROM 2012-03-19 TO TODAY THERE ARE 0 MONTHS

<?
include "MySQL_RAY_temp_sasnaktiv.inc";

$link = mysql_connect ($dbhost, $dbusername, $dbuserpass);
if (!mysql_select_db($dbname)) die(mysql_error());

     $getlist="SELECT * FROM `Members`"; //select e-mails in ABC order

      $getlist2=mysql_query($getlist) or die("Could not get your members list");

$LastPaymentDate= "$getlist3[payment_made]";
$PaymentDueDate = date("Y-m-d");

$NextMonth = mktime(0, 0, 0, date("m")+1, date("d"), date("y"));
$NxtBillDate = date("Y-m-01", $NextMonth); // THIS SHOULD BE 2012-04-01  BUT IT RETURNS 2012-05-01. WHY???

echo "<pre>";

date_default_timezone_set('America/New_York');

function howManyMonths($alpha, $omega)
{
    // NORMALIZE THE OLD MONTH
    $a = strtotime($alpha);
    $a = date("Y-m-d");
    if (!$a) return "ERROR $alpha";

    // NORMALIZE THE NEW MONTH
    $z = strtotime($omega);
    if (!$z) return "ERROR $omega";
    $z = date('Y-m-1', $z);

    $n = 0;
    while ($a < $z)
    {
        $a = date('Y-m-1', strtotime($a . ' + 1 MONTH'));
        $n++;
    }
    // ACTIVATE THIS LINE FOR TESTING
    echo PHP_EOL . "FROM $alpha TO $omega THERE ARE $n MONTHS";
    return $n;
}
// TEST CASES
howmanymonths("$LastPaymentDate", "$PaymentDueDate");
howmanymonths("$LastPaymentDate", "$NxtBillDate");
howmanymonths('December 2011', 'March 2012');

// ANY DAY IN THIS MONTH
$x = rand(1,28);
howmanymonths( date("Y-m-$x"), 'TODAY');
?>

Open in new window

ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
You can also do it straigh in your SQL SELECT query, but for that I need to know how you're storing that data. You can however check the MySQL manual, the date and time functions section.
Thanks designatedinitializer

I think that's working, but tell me why am I getting April (05) instead of May (04)
with the following code:
$NextMonth = mktime(0, 0, 0, date("m")+1, date("d"), date("y"));
$NxtBillDate = date("Y-m-01", $NextMonth); // THIS SHOULD BE 2012-04-01  BUT IT RETURNS 2012-05-01. WHY???

Open in new window

because you have
date("m")+1

?
What should it be?
date("m")   returns this month 03
date("m")+0 returns this month 03
date("m")+1 returns 2 months ahead to 05
date("m")+2 also returns 2 months ahead to 05
date("m")+3 returns 4 months ahead to 07

What happened to 04 & 06?
Why is this so screwy?
FROM 2012-03-09 TO 2012-05-01 THERE ARE 1 MONTHS  -- THE MONTH COUNT SEEMS CORRECT BUT THIS SHOULD BE 2012-04-01   IT ACTUALLY RETURNS 2012-05-01. WHY???
This only happens today, March 31, because April 31 does not exist.  So the Unix timestamp generated by mktime() flops over to the next month.  The meaning of the term "month" is ambiguous.  Unlike weeks that have seven days every week, the number of days in a month can change.  I think you'll be OK if you use the function I posted earlier.  Best of luck with your project, ~Ray
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks Ray,
Will that function properly during months that have only 30 days or 28 days?
Sas
Yes, I think so.  It only looks at the first day of the month - not the number of days in the month.
Thanks guys,
Both solutions seem to work for me. I just wish I could add more points.
Sas
For what it is worth, the ultimate answer is still the equation I posted in 37759579, just different variable names.   ;)

LAPSEDMONTHS = (FUTUREYEAR - LASTPAYMENTYEAR) * 12 + FUTUREMONTH - LASTPAYMENTMONTH.
That may be the case, but you never got back to me about my follow up question:

"How do I determine from my variables "FUTUREYEAR" and "LASTPAYMENTYEAR"?
And shall I assume "FUTUREMONTH" and "LASTPAYMENTMONTH" would follow the same logic?"

If you had I might have had the solution much earlier than I did.
Just please be aware that I do indeed appreciate your help.
Thanks,
Sas
Agreed, I had the premise that you knew how to assign variable names and put the values in them, but the engineering problem was a single line of code that dropped the days of the month and took (YYYY * 12 + M) and subtracted the difference.  I'm not complaining, not asking or implying points, just pointing out that this was a one-line of code simple solution ;)
dlethe:
you were also assuming that the data was separated in years, and months, and that both were integers you could simply add up and multiply.
The question showed dates in the form of strings...
I appreciate simplicity. I hope we can work together on my next problem child.
Thanks for your help,
Sas
same here, glad it worked out for you.