Solved

# How to count months that span multiple years

Posted on 2012-09-02
320 Views
I'm trying to figure out how to count months that span multiple years. I was trying to do it this way:

``````        \$start_ts 	= 	1331245800; //2012-03-08
\$start_ts	=	strtotime(date('Y-m-1',\$start_ts));

\$stop_ts	=	1362200400; //2013-03-31
//\$stop_ts	=	1359781200; //2013-02-28
//\$stop_ts 	=	1346458500;	//2012-08-31

\$num_days	=	date('t',\$stop_ts); // how many days are in the month
\$stop_ts	=	strtotime(date('Y-m-'.\$num_days,\$stop_ts)); // set timestamp for last day of the month that the timestamp falls in.

// Figure out how many months are in the date range
\$start_str	=	date('Y-m-d', \$start_ts);
\$stop_str	=	date('Y-m-d', \$stop_ts);
\$d1	= new DateTime(\$start_str);
\$d2	= new DateTime(\$stop_str);
\$month_count = (\$d1->diff(\$d2)->m); // Months in date range

echo 'Number of Months: '.\$month_count;
``````

But it won't go past 11 months. If I uncomment the \$stop_ts for 2013-02-28 it works fine, but if I leave it as is above it shows 0 months. Any ideas? Am I missing something or is this a limitation of the function?

Thanks,
Brian
0
Question by:bacamaro

LVL 16

Accepted Solution

``````\$d1 = strtotime("2009-09-01");
\$d2 = strtotime("2010-05-01");
\$min_date = min(\$d1, \$d2);
\$max_date = max(\$d1, \$d2);
\$i = 0;

while ((\$min_date = strtotime("+1 MONTH", \$min_date)) <= \$max_date) {
\$i++;
}
echo \$i; // 8
``````
0

LVL 107

Expert Comment

count months that span multiple years
Please give us a plain-language explanation of what you want to achieve here.  We do not need technical details, just the basic facts.  Thanks, ~!Ray
0

LVL 49

Assisted Solution

Depends on how accurate you want to be and how you want to handle partial months but here are some ideas.
``````<pre>
<?php
// Not sure what
\$dt1 = '2012-08-11';
\$dt2 = '2008-05-31';

// Get Year,  month, day values for the date
list(\$y1, \$m1, \$d1) = explode('-', \$dt1);
list(\$y2, \$m2, \$d2) = explode('-', \$dt2);

// If older date month is higher decrement newer date for the carry
if (\$d2 > \$d1) {
// compensate for year boundaries
if (--\$m1 == 0) {
\$y1--;
\$m1 = 12;
}
}
// If older month is higher compansate by adding some months
if (\$m2 > \$m1) {
\$m1+=12;
\$y1--;
}
// Work out the months on what is left
\$months = (\$y1-\$y2)*12 + (\$m1 - \$m2);
echo \$months . "\n";

// Alternative method
// Get time in seconds for each date
\$t1 = strtotime(\$dt1);
\$t2 = strtotime(\$dt2);

// 1 day = 86400 seconds
// working on 365.25 days in a year with 12 months gives average
// days per month of 30.3475
// Months = seconds / (86400 * 30.4375)

echo "Seconds: " . (\$t1-\$t2) . "\n";
echo "Days: " . (\$t1-\$t2) / 86400 . "\n";

echo "Months: " . (\$t1-\$t2) / (86400 * 30.4375) . "\n";
?>
</pre>
``````
0

LVL 107

Expert Comment

0

LVL 107

Assisted Solution

See http://www.laprbass.com/RAY_temp_bacamaro.php

This seems to test out in a way that appears numerically correct.  Check lines 38-39 to be sure you're getting the answer you want in the narrow edge cases.

``````<?php // RAY_temp_bacamaro.php
error_reporting(E_ALL);

// REQUIRED FOR PHP 5.1+
date_default_timezone_set('America/Chicago');

// SOME TEST CASES
\$data = array
( array( 'lo' => '2012-03-08', 'hi' => '2012-03-07' )
, array( 'lo' => '2012-03-08', 'hi' => '2012-03-31' )
, array( 'lo' => '2012-03-08', 'hi' => '2012-04-01' )
, array( 'lo' => '2012-03-08', 'hi' => '2012-05-23' )
, array( 'lo' => '2012-03-08', 'hi' => '2014-03-31' )
, array( 'lo' => '2012-03-08', 'hi' => '2012-02-01' )
, array( 'lo' => '2012-03-08', 'hi' => '2013-01-30' )
)
;

// RUN THE TESTS
foreach (\$data as \$lohi)
{
\$cnt = howManyMonths(\$lohi["lo"], \$lohi["hi"]);
if (\$cnt === FALSE)
{
echo "<br/>FROM {\$lohi["lo"]} TO {\$lohi["hi"]} MONTHS ARE OUT OF ORDER";
continue;
}
echo "<br/>FROM {\$lohi["lo"]} TO {\$lohi["hi"]} WE COUNT \$cnt MONTHS";
echo PHP_EOL;
}

function howManyMonths(\$lo, \$hi)
{
\$lo = date('Y-m-01', strtotime(\$lo));
\$hi = date('Y-m-01', strtotime(\$hi));
if (\$lo > \$hi) return FALSE;

// DECIDE IF DATES IN THE SAME MONTH SHOULD RENDER ZERO MONTHS OR ONE MONTH
\$cnt = 0;
while (\$lo < \$hi)
{
\$cnt++;
\$lo = date('Y-m-01', strtotime("\$lo + 1 MONTH"));
}
return \$cnt;
}
``````
HTH, ~Ray
0

LVL 49

Expert Comment

Why the rating of Good - have you read the rating guide - what in the solutions above did not answer your question?
0

LVL 107

Expert Comment

Given a tested and working code sample, it seem strange that you would mark the grade down.  Please explain what you expected that you did not get here, thanks. ~Ray
0

## Featured Post

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 …
A colleague recently asked me about how to give his client a small part of the web site that could be completely under the client's control.  Since I have done this sort of thing before to add emergency banners to a web site, I decided I would creat…
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…
The viewer will learn how to dynamically set the form action using jQuery.