sharklaser12345
sharklaser12345

Reputation: 11

Create array of dates based on inputs

Given these two YYYYMM strings:

$start = "201301";
$end = "201303";

I would like to derive an array like this:

array (
  0 => 
  array (
    0 => '20130101',
    1 => '20130131',
  ),
  1 => 
  array (
    0 => '20130201',
    1 => '20130228',
  ),
  2 => 
  array (
    0 => '20130301',
    1 => '20130331',
  ),
)

I've tried a few things with date() and mktime() but nothing decent so far.

What's a nice way to do this?

Upvotes: 0

Views: 190

Answers (7)

Narek
Narek

Reputation: 3823

With DateTime:

$start = "201301";
$end = "201303";

$dateNiceStart = substr($start,0,4).'-'.substr($start,4).'-01';
$dateNiceEnd = substr($end,0,4).'-'.substr($end,4).'-';

// Days count in month
$endDays = date('t',strtotime($dateNiceEnd.'01'));
$dateNiceEnd .= $endDays;

$startObj = new DateTime($dateNiceStart);
$endObj = new DateTime($dateNiceEnd);

$temp = clone $startObj;

$arr = array();
// Adding first month
//Using first day and last day
$temp->modify( 'first day of this month' );
$start = $temp->format('Ymd');
$temp->modify( 'last day of this month' );
$end = $temp->format('Ymd');

$arr[] = array($start, $end);
do{
    // for next month
    $temp->modify( 'first day of next month' );
    $start = $temp->format('Ymd');
    $temp->modify( 'last day of this month' );
    $end = $temp->format('Ymd');

    $arr[] = array($start, $end);

    // This line edited to work properly in different years, thanks to @Adidi
    $interval = $endObj->diff($temp)->format('%y%m%d');
}
while ($interval!=0);

print_R($arr);

Main key is first/last day of next/this month usage.

Upvotes: 2

Sabari
Sabari

Reputation: 6335

You can try with these functions :

function get_date_range ($start, $end) {

    $dates = array();

    $start = strtotime($start .'01');
    $end    = strtotime($end .'01');

    while ($start <= $end) {
        $dates [] = array(date('Ym01', $start), date('Ymt', $start));
        $start  = strtotime(add_month(date('Y-m-01', $start), 1));
    }

    return $dates;
}

function add_month($date_value, $months, $format = 'm/d/Y') {
    $date = new DateTime($date_value);
    $start_day = $date->format('j');

    $date->modify("+{$months} month");
    $end_day = $date->format('j');

    if ($start_day != $end_day)
        $date->modify('last day of last month');

    return $date->format($format);
}

$start = "201301";
$end    = "201303";

$dates = get_date_range($start, $end);

print_r($dates);

Here the add_month function will help you to avoid problems with the date when adding one month to January 31st.

If you use strtotime it will go to March when adding 1 month to January 31st.. Output will be :

Array
(
    [0] => Array
        (
            [0] => 2013-01-01
            [1] => 2013-01-31
        )

    [1] => Array
        (
            [0] => 2013-02-01
            [1] => 2013-02-28
        )

    [2] => Array
        (
            [0] => 2013-03-01
            [1] => 2013-03-31
        )

)

Hope this helps you :)

Upvotes: 0

Adidi
Adidi

Reputation: 5253

Working solution:

$start = "201301";
$end = "201309";

function getDateTimeByString($str_date){
    preg_match('/^([\d]{4})([\d]{2})$/',$str_date,$matches);
    $dt = null;
    if($matches){
        $dt = new DateTime();
        $dt->setDate($matches[1],$matches[2],1);   
    }
    return $dt;      
}


$start_dt = getDateTimeByString($start);
$end_dt = getDateTimeByString($end);

$output = array();

while($start_dt->getTimestamp() <= $end_dt->getTimestamp()){
    $arr = array(); 
    $arr[] = $start_dt->format('Ymd');
    $start_dt->modify('last day of this month');
    $arr[] = $start_dt->format('Ymd');

    $output[] = $arr;  

    $start_dt->modify('first day of next month');
}


print_r($output);

prints:

Array
(
    [0] => Array
        (
            [0] => 20130101
            [1] => 20130131
        )

    [1] => Array
        (
            [0] => 20130201
            [1] => 20130228
        )

    [2] => Array
        (
            [0] => 20130301
            [1] => 20130331
        )

    [3] => Array
        (
            [0] => 20130401
            [1] => 20130430
        )

    [4] => Array
        (
            [0] => 20130501
            [1] => 20130531
        )

    [5] => Array
        (
            [0] => 20130601
            [1] => 20130630
        )

    [6] => Array
        (
            [0] => 20130701
            [1] => 20130731
        )

    [7] => Array
        (
            [0] => 20130801
            [1] => 20130831
        )

    [8] => Array
        (
            [0] => 20130901
            [1] => 20130930
        )

)

Upvotes: 0

Svetoslav
Svetoslav

Reputation: 4686

Here is easy way to loop it..

$start  = "201301";
$end    = "201303";

$start_time = strtotime(implode('-',str_split($start,4)));
$end_time = strtotime(implode('-',str_split($end,4)));

$array = array();
if($start_time <= $end_time){
    while($start_time <= $end_time){
        $month = date('F', $start_time);
        $array[] = array(
            date('Ymd', strtotime("first day of {$month}", $start_time)),
            date('Ymd', strtotime("last day of {$month}", $start_time)));
        $start_time = strtotime("next month", $start_time);
    }
}

Upvotes: 1

Alix
Alix

Reputation: 256

http://www.php.net/manual/en/function.date.php

Which you need is format string "t":

t Number of days in the given month 28 through 31

Upvotes: 1

Ja͢ck
Ja͢ck

Reputation: 173562

You can iterate over the months like so:

function date_range($start, $end)
{
    $start = strtotime("$start01");
    $end = strtotime("$end01");

    $res = array();

    while ($start < $end) {
        $next = strtotime("+1 month -1 day", $start);
        $res[] = array(
            date('Ymd', $start),
            date('Ymd', $next),
        );
        $start = $next;
    }

    return $res;
}

Upvotes: 0

uruk
uruk

Reputation: 1306

Something like this?

for($i=1;$i<=12;$i++) {
    $first = '2013'.($i<10 ? '0'.$i : $i).'01';
    $last = date('Ymt', strtotime($first));
    $myArray[] = array($first, $last);
}

Not tested.

Upvotes: 0

Related Questions