Check for consecutive dates within a set and return as range

后端 未结 1 840
傲寒
傲寒 2020-11-27 19:56

I have arrays of dates Y-m-d format that may be any combination of ten set dates that are one day apart.

e.g. Here is the full set:

2011-01-01, 2011-01-02,

相关标签:
1条回答
  • 2020-11-27 20:35

    Bit of a quick answer so sorry about the lack of implementation but assuming you are using 5.3 and the dates are ordered chronologically, you could convert each date to a DateTime object (if they aren't already) and then iterate over the array using DateTime::diff() to generate a DateInterval object which you could use to compare the current date in the iteration with the last. You could group your consecutive dates into sub arrays and use shift() and pop() to get the first and last days in that sub array.

    EDIT

    I had a think about this. Pretty rough and ready implementation follows, but it should work:

    // assuming a chronologically
    // ordered array of DateTime objects 
    
    $dates = array(
        new DateTime('2010-12-30'), 
        new DateTime('2011-01-01'), 
        new DateTime('2011-01-02'), 
        new DateTime('2011-01-03'), 
        new DateTime('2011-01-06'), 
        new DateTime('2011-01-07'), 
        new DateTime('2011-01-10'),
    );
    
    // 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 = sprintf('%s', $startDate->format('D j M'));
    
        // 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(' to %s', $endDate->format('D j M'));
        }
    
        echo "<p>$str</p>";
    }
    

    Outputs:

    Thu 30 Dec
    Sat 1 Jan to Mon 3 Jan
    Thu 6 Jan to Fri 7 Jan
    Mon 10 Jan
    
    0 讨论(0)
提交回复
热议问题