How can I shrink two dates in to one date range?

I need to display date ranges like the following:

  • May 5-7, 2015
  • April 29-May 5, 2015
  • December 30 2015-January 1, 2016

I'm provided a start date and an end date as PHP date objects. Is there a way I can parse those with PHP to output as needed?


EDIT: I think you guys are misunderstanding what I'm looking to do.

I've got a WordPress events plugin that outputs a start date and an end date. If an event has a start date of May 4, 2015, and an end date of May 7, 2015, I need to display this:

<h4>Event Title</h4>
<p>When: <time>May 4-7, 2015</time></p>

I don't need to display each date between the given dates; that's easy enough for me to figure out on my own.


EDIT 2: Alright, just to make sure I'm being completely clear:

I'm using the Tri.be Events plugin to allow a user to create a calendar of events. On the front page for this WordPress site, I need to display a list of upcoming events. Each event should be output like this:

This event should be output like this:

<article>
    <h4><a href="/path/to/event/">Systematic Implementation of Advance Care Planning in a Diverse City</a></h4>
    <p>
        <a href="/path/to/event/">
            Aging in America Conference - Chicago, IL<br />
            <time datetime="2015-03-23">March 23-27, 2015</time>
        </a>
    </p>
</article>

The bit I'm having trouble with is the <time> element. The answers below seem to indicate that I want to output the time in this format:

<time datetime="2015-03-23">March 23, 2015 - March 27, 2015</time>

This is incorrect. If that where the case, I could easily output this on my own. The correct format is:

<time datetime="2015-03-23">March 23-27, 2015</time>

Thus, the question is: "How can I shrink two dates in to one date range?"

Answers


EDIT 2:

I have updated the function with some date format.

Output will be:

Event title

When: Feb 28, 2010 - Mar 2, 2010

Event title

When: Mar 4, 2010 - Mar 5, 2010

Event title

When: Dec 31, 2010 - Jan 5, 2011

EDIT:

I found this (by searching) -- > Check for consecutive dates within a set and return as range

The code below isn't mine. It's an old post from @Darragh

I have made some minor changes to the code to fit the OP's question.

    // assuming a chronologically
    // ordered array of DateTime objects 

    $dates = array(         
          new DateTime('2010-02-28'), 
          new DateTime('2010-03-01'), 
          new DateTime('2010-03-02'), 
          new DateTime('2010-03-04'), 
          new DateTime('2010-03-05'), 
          new DateTime('2010-12-31'),
          new DateTime('2011-01-01'), 
          new DateTime('2011-01-02'), 
          new DateTime('2011-01-03'), 
          new DateTime('2011-01-04'), 
          new DateTime('2011-01-05'),
    );

    // process the array

    $lastDate = null;
    $ranges = array();
    $currentRange = array();

    foreach ($dates as $date) {    

        if (null === $lastDate) {
            $currentRange[] = $date;
        } else {

            // get the DateInterval object
            $interval = $date->diff($lastDate);

            // DateInterval has properties for 
            // days, weeks. months etc. You should 
            // implement some more robust conditions here to 
            // make sure all you're not getting false matches
            // for diffs like a month and a day, a year and 
            // a day and so on...

            if ($interval->days === 1) {
                // add this date to the current range
                $currentRange[] = $date;    
            } else {
                // store the old range and start anew
                $ranges[] = $currentRange;
                $currentRange = array($date);
            }
        }

        // end of iteration... 
        // this date is now the last date     
        $lastDate = $date;
    }

    // messy... 
    $ranges[] = $currentRange;

    // print dates

        foreach ($ranges as $range) {

    // there'll always be one array element, so 
    // shift that off and create a string from the date object 
    $startDate = array_shift($range);
    $str = "<h4>Event title</h4>";
    $str .= "<p>When: ";
    $str .= "<time>"; 
    $str .= sprintf('%s', $startDate->format('M j, Y'));
    // if there are still elements in $range
    // then this is a range. pop off the last 
    // element, do the same as above and concatenate
    if (count($range)) {
        $endDate = array_pop($range);
        $str .= sprintf(' - %s', $endDate->format('M j, Y'));
        $str .= "</time></p>";
    }

    echo "<p>$str</p>";
}

Old answer (based on original question).

$start_date = new DateTime( '2015-05-01' );
$end_date = new DateTime( '2015-05-04' );
$end_date = $end_date->modify( '+1 day' ); 

$interval = new DateInterval('P1D');
$daterange = new DatePeriod($start_date, $interval ,$end_date);

foreach($daterange as $date){
    echo $date->format("M d, Y") . "<br>";
}

// Output
// May 01, 2015
// May 02, 2015
// May 03, 2015
// May 04, 2015

<article>
    <h4><a href="/path/to/event/">Systematic Implementation of Advance Care Planning in a Diverse City</a></h4>
    <p>
        <a href="/path/to/event/">
            Aging in America Conference - Chicago, IL<br />
            <time datetime="2015-03-23/2015-03-27">March 23&ndash;27 2015</time>
        </a>
    </p>
</article>

Edit

Complete example with PHP-code above.

Output

Mar 23, 2015–Mar 27, 2015

    // assuming a chronologically
    // ordered array of DateTime objects 

    $dates = array(         
          new DateTime('2015-03-23'), 
          new DateTime('2015-03-24'), 
          new DateTime('2015-03-25'), 
          new DateTime('2015-03-26'), 
          new DateTime('2015-03-27')          
    );

    // process the array

    $lastDate = null;
    $ranges = array();
    $currentRange = array();

    foreach ($dates as $date) {    

        if (null === $lastDate) {
            $currentRange[] = $date;
        } else {

            // get the DateInterval object
            $interval = $date->diff($lastDate);

            // DateInterval has properties for 
            // days, weeks. months etc. You should 
            // implement some more robust conditions here to 
            // make sure all you're not getting false matches
            // for diffs like a month and a day, a year and 
            // a day and so on...

            if ($interval->days === 1) {
                // add this date to the current range
                $currentRange[] = $date;    
            } else {
                // store the old range and start anew
                $ranges[] = $currentRange;
                $currentRange = array($date);
            }
        }

        // end of iteration... 
        // this date is now the last date     
        $lastDate = $date;
    }

    // messy... 
    $ranges[] = $currentRange;

    // print dates

    foreach ($ranges as $range) {

    // there'll always be one array element, so 
    // shift that off and create a string from the date object 
    $startDate = array_shift($range);
    $str = "<h4>Event title</h4>";
    $str .= "<p>When: ";
    $str .= "<time>"; 
    $str .= sprintf('%s', $startDate->format('M j, Y'));
    // if there are still elements in $range
    // then this is a range. pop off the last 
    // element, do the same as above and concatenate
    if (count($range)) {
        $endDate = array_pop($range);
        $str .= sprintf(' - %s', $endDate->format('M j, Y'));
        $str .= "</time></p>";
    }

}

echo "<time datetime=".$startDate->format('M j, Y')."/".$endDate->format('M j, Y').">".$startDate->format('M j, Y')."&ndash;".$endDate->format('M j, Y')."</time>";

//OUTPUT
// Mar 23, 2015–Mar 27, 2015

Need Your Help

What's the best way to model recurring events in a calendar application?

ruby algorithm calendar data-modeling recurrence

I'm building a group calendar application that needs to support recurring events, but all the solutions I've come up with to handle these events seem like a hack. I can limit how far ahead one can ...

Call Block_Release inside block to be released

objective-c objective-c-blocks grand-central-dispatch

Is it possible to release a block inside itself? For the compiler it's fine, but I'm not sure if at runtime it will crash, since it releases memory that is executed at the same time.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.