Pooya
Pooya

Reputation: 1558

How to list all months between two dates

I'm trying to list all months between two dates.

For example; start date is: 2010-12-02 and last date is: 2012-05-06

I want to list something like this:

2010-12
2011-01
2011-02
2011-03
2011-04
.
.
.
2012-04
2012-05

This is what I have tried and it is not working at all:

    $year_min = 2010;
    $year_max = 2012;
    $month_min = 12;
    $month_max = 5;
    for($y=$year_min; $y<=$year_max; $y++)
    {
        for($m=$month_min; $m<=$month_max; $m++)
        {
            $period[] = $y.$m;
        }
    }

Upvotes: 72

Views: 91431

Answers (7)

denesis
denesis

Reputation: 73

Hope it helps someone.

Function returns Array of months in format: YYYY-MM. Strarting from: $od, ending month: $do

function monthsInRange(string $od, string $do){
    $yms = [];

    if($od > $do)
        return false;

    $ym = $od;

    do{
        $yms[] = $ym;
        
        $y = (int)substr($ym,0,4);
        $m = (int)substr($ym,5,2);

        if($m == 12){
            $ny = $y+1;
            $nm = 1;
        }else{
            $ny = $y;
            $nm = $m+1;
        }

        $ym = $ny.'-'.str_pad($nm, 2, '0', STR_PAD_LEFT);
    }
    while($ym <= $do);

    return $yms;
}

Upvotes: 0

sulayman
sulayman

Reputation: 137

function getMonthsInRange($startDate, $endDate)
{
    $months = array();

    while (strtotime($startDate) <= strtotime($endDate)) {
        $months[] = array(
            'year' => date('Y', strtotime($startDate)),
            'month' => date('m', strtotime($startDate)),
        );

        // Set date to 1 so that new month is returned as the month changes.
        $startDate = date('01 M Y', strtotime($startDate . '+ 1 month'));
    }

    return $months;
}

Upvotes: 13

Peter
Peter

Reputation: 741

October 2021 Update
If you have dates selected by the user, here's a solution

$from = date('Y-m-d', strtotime($_POST['from']));
$to = date('Y-m-d', strtotime($_POST['to']));

$counter = 1;
$max_date = strtotime($to);
$current_date = strtotime($from);
$dates = [];
$months = [];
$loop = true;
while($loop) {
    if(strtotime(date('Y-m-d',$current_date)." +".$counter."days") >= $max_date) $loop = false;
    else {
        $current_date = strtotime(date('Y-m-d', $current_date)." +".$counter."days");
        $date = date('Y-m-d', $current_date);
        $dates[] = $date;
        $months[] = date('Y-m', $current_date);
        $counter++;
    }
}
$months = array_unique($months);
echo '<pre>';
print_r($dates);
echo '<br>';
print_r($months);
echo '</pre>';

Upvotes: 0

Chandan Sharma
Chandan Sharma

Reputation: 2519

In Laravel,

$period = \Carbon\CarbonPeriod::create('2017-06-28', '1 month', '2019-06-01');

foreach ($period as $dt) {
     echo $dt->format("Y-m") . "<br>\n";
}

Upvotes: 3

SteeveDroz
SteeveDroz

Reputation: 6136

You must make a difference between two months of the same year and two months of different years.

$year_min = substr($row['contractStart'], 0, 4);
$year_max = substr($row['contractEnd'], 0, 4);
$month_min = substr($row['contractStart'], 5, 2);
$month_min = substr($row['contractEnd'], 5, 2);
$period = array();
try {
  if ($year_min > $year_max)
    throw new Exception();
  else if ($year_min == $year_max)
    if ($month_min > $month_max)
      throw new Exception();
    for ($month = $month_min; $month <= $month_max; $month++) {
      $period[] = $month . '-' . $year;
    }
  else {
    for ($month = $month_min; $month <= 12; $month++) {
      $period[] = $month . '-' . $year_min;
    }
    for ($year = $year_min + 1; $year < $year_max; $year++) {
      for ($month = $month_min; $month <= $month_max; $month++) {
        $period[] = $month . '-' . $year;
      }
    }
    for ($month = 1; $month <= $month_max; $month++) {
      $period[] = $month . '-' . $year_max;
    }
  }
  implode("<br />\r\n", $period);
}
catch (Exception $e) {
  echo 'Start date occurs after end date.'
}

That's for the hard way. Now there is a quick and easy way that is already given as an answer which I recommend you to choose.

Upvotes: 10

John Conde
John Conde

Reputation: 219804

PHP 5.3

$start    = new DateTime('2010-12-02');
$start->modify('first day of this month');
$end      = new DateTime('2012-05-06');
$end->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 month');
$period   = new DatePeriod($start, $interval, $end);

foreach ($period as $dt) {
    echo $dt->format("Y-m") . "<br>\n";
}

See it in action

PHP 5.4 or newer

$start    = (new DateTime('2010-12-02'))->modify('first day of this month');
$end      = (new DateTime('2012-05-06'))->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 month');
$period   = new DatePeriod($start, $interval, $end);

foreach ($period as $dt) {
    echo $dt->format("Y-m") . "<br>\n";
}

The part where we modify the start and end dates to the first of the month is important. If we didn't, and the current day higher then the last day in February (i.e. 28 in non-leap years, 29 in leap years) this would skip February.

Upvotes: 239

CptAJ
CptAJ

Reputation: 1166

This was my solution since DateTime is not available in my server environment.

$a = "2007-01-01";
$b = "2008-02-15";

$i = date("Ym", strtotime($a));
while($i <= date("Ym", strtotime($b))){
    echo $i."\n";
    if(substr($i, 4, 2) == "12")
        $i = (date("Y", strtotime($i."01")) + 1)."01";
    else
        $i++;
}

Try it out: http://3v4l.org/BZOmb

Upvotes: 6

Related Questions