Solved

PHP Number of months between 2 dates

Posted on 2012-03-23
25
393 Views
Last Modified: 2012-06-22
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
0
Comment
Question by:sasnaktiv
  • 10
  • 6
  • 5
  • +1
25 Comments
 
LVL 47

Expert Comment

by:dlethe
ID: 37759579
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)
0
 
LVL 1

Author Comment

by:sasnaktiv
ID: 37759688
Thanks.
How do I determine from my variables "FUTUREYEAR" and "LASTPAYMENTYEAR"?

And shall I assume "FUTUREMONTH" and "LASTPAYMENTMONTH" would follow the same logic?
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 37759698
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.
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/A_201-Handling-date-and-time-in-PHP-and-MySQL.html
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 37759726
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
0
 
LVL 1

Author Comment

by:sasnaktiv
ID: 37759748
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
0
 
LVL 7

Expert Comment

by:designatedinitializer
ID: 37789865
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.
0
 
LVL 108

Assisted Solution

by:Ray Paseur
Ray Paseur earned 300 total points
ID: 37790789
Sorry to have taken so long to get back to you.  I wrote a demonstration code example, but lost track of the question on EE so I couldn't figure out where to put it!
See http://www.laprbass.com/RAY_temp_sasnaktiv.php
Outputs:
FROM January 2012 TO March 2012 THERE ARE 2 MONTHS
FROM December 2011 TO March 2012 THERE ARE 3 MONTHS
FROM December 2011 TO TODAY THERE ARE 3 MONTHS
FROM -30 DAYS TO TOMORROW THERE ARE 1 MONTHS
FROM -3 DAYS TO TODAY THERE ARE 0 MONTHS
FROM LAST MONTH TO TODAY THERE ARE 0 MONTHS
FROM 2012-03-5 TO TODAY THERE ARE 0 MONTHS
<?php // RAY_temp_sasnaktiv.php
error_reporting(E_ALL);
echo "<pre>";


// HOW MANY MONTHS BETWEEN TWO DATES?


date_default_timezone_set('America/Chicago');

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

    // 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('January 2012', 'March 2012');
howmanymonths('December 2011', 'March 2012');
howmanymonths('December 2011', 'TODAY');
howmanymonths('-30 DAYS', 'TOMORROW');
howmanymonths('-3 DAYS', 'TODAY');
howmanymonths('LAST MONTH', 'TODAY');

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

Open in new window

0
 
LVL 1

Author Comment

by:sasnaktiv
ID: 37791556
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

0
 
LVL 1

Author Comment

by:sasnaktiv
ID: 37791558
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

0
 
LVL 7

Accepted Solution

by:
designatedinitializer earned 200 total points
ID: 37791600
I ran your code exactly as you posted it and I get the following error.
What can be done to resolve this error?
It means your PHP installation doesn't support the DateTime class.
You can do it simply like this:
<?php
// Find how many months have passed between date1 and date2
$date1 = "2011-11-21";
$date2 = "2012-04-01";

$one = explode('-',$date1);
$two = explode('-',$date2);

$aMonths = (int)$one[0]*12+(int)$one[1];
$bMonths = (int)$two[0]*12+(int)$two[1];
$months  = $bMonths-$aMonths;

print "From $date1 to $date2 there are $months whole months.";
?>

Open in new window

0
 
LVL 7

Expert Comment

by:designatedinitializer
ID: 37791604
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.
0
 
LVL 1

Author Comment

by:sasnaktiv
ID: 37791629
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

0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 7

Expert Comment

by:designatedinitializer
ID: 37791728
because you have
date("m")+1

?
0
 
LVL 1

Author Comment

by:sasnaktiv
ID: 37791748
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?
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 37791764
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
0
 
LVL 108

Assisted Solution

by:Ray Paseur
Ray Paseur earned 300 total points
ID: 37791770
Afterthought... You might also try this for mktime()

$NextMonth = mktime(0, 0, 0, date("m")+1, '1', date("y"));
0
 
LVL 1

Author Comment

by:sasnaktiv
ID: 37791796
Thanks Ray,
Will that function properly during months that have only 30 days or 28 days?
Sas
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 37792083
Yes, I think so.  It only looks at the first day of the month - not the number of days in the month.
0
 
LVL 1

Author Closing Comment

by:sasnaktiv
ID: 37797957
Thanks guys,
Both solutions seem to work for me. I just wish I could add more points.
Sas
0
 
LVL 47

Expert Comment

by:dlethe
ID: 37798056
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.
0
 
LVL 1

Author Comment

by:sasnaktiv
ID: 37798310
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
0
 
LVL 47

Expert Comment

by:dlethe
ID: 37798367
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 ;)
0
 
LVL 7

Expert Comment

by:designatedinitializer
ID: 37798426
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...
0
 
LVL 1

Author Comment

by:sasnaktiv
ID: 37798457
I appreciate simplicity. I hope we can work together on my next problem child.
Thanks for your help,
Sas
0
 
LVL 47

Expert Comment

by:dlethe
ID: 37798511
same here, glad it worked out for you.
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Popularity Can Be Measured Sometimes we deal with questions of popularity, and we need a way to collect opinions from our clients.  This article shows a simple teaching example of how we might elect a favorite color by letting our clients vote for …
Author Note: Since this E-E article was originally written, years ago, formal testing has come into common use in the world of PHP.  PHPUnit (http://en.wikipedia.org/wiki/PHPUnit) and similar technologies have enjoyed wide adoption, making it possib…
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now