0

I have an array of dates like this:

[Room 01 - DBL] => Array
            (
                [0] => Mon 23-06-2014
                [1] => Tue 24-06-2014
                [2] => Wed 25-06-2014
                [3] => Sat 28-06-2014
                [4] => Sun 29-06-2014
            )

        [Room 02 - TWN] => Array
            (
                [0] => Tue 24-06-2014
                [1] => Wed 25-06-2014
                [2] => Sat 28-06-2014
                [3] => Sun 29-06-2014
            )

You can see that neither room has the date for the thursday or friday. I want to be able to create a date range (either a DateTime Interval object or not - don't mind) for each group of dates. So Room 02 - TWN should give me two date periods - one for Tue-Wed and another for Sat-Sun. How would I go about this? I know how to make a single date time period using the first and last items in the array but don't know how to detect if there is a gap...

Ralphonz
  • 633
  • 1
  • 9
  • 22
  • Loop through the dates from start to finish. If the doff between two dates is greater than 1 day, there's a gap. (Compares dates at midnight). – John Conde Jun 23 '14 at 17:46

1 Answers1

1

I'm not very clear about what you're trying to accomplish. Anyway, in the general case, you can do something like this.

The idea is to run the whole array of items, and if the "next" item is contiguous to a candidate interval you already have, you extend the interval. Else, the candidate interval becomes a standalone interval, and the item that just failed the check gives birth to a new candidate interval.

You need two functions: one that, given two items, returns whether it's true or false that they are contiguous; the other, given two items, returns an "interval" with those two items as extremes.

An empty $items will return an empty interval.

function build_intervals($items, $is_contiguous, $make_interval) {

    $intervals = array();
    $end   = false;
    foreach ($items as $item) {
        if (false === $end) {
            $begin = $item;
            $end   = $item;
            continue;
        }
        if ($is_contiguous($end, $item)) {
            $end = $item;
            continue;
        }
        $intervals[] = $make_interval($begin, $end);
        $begin = $item;
        $end   = $item;
    }
    if (false !== $end) {
        $intervals[] = $make_interval($begin, $end);
    }
    return $intervals;
}

For numbers, you can use

$interv = build_intervals(
    array( 1, 2, 3,     5, 6,    9, 10, 11,    13,   17, 18 ),
    function($a, $b) { return ($b - $a) <= 1; },
    function($a, $b) { return "{$a}..{$b}"; }
);

print_r($interv);

returns

Array
(
    [0] => 1..3
    [1] => 5..6
    [2] => 9..11
    [3] => 13..13
    [4] => 17..18
)

With dates, you can keep them as DateTime and DateTimeIntervals. If you use timestamps, then you must supply a contiguousness criterion that's valid for timestamps. This can be awkward if you have two timestamps that are just before and after midnight the following day. To be sure, you should take times at always around midday (i.e., given two dates, get the timestamps of those dates at midday. If they're less than 36 hours apart, they're two adjacent days.

    function($a, $b) { 
        $a_ts = strtotime("{$a} 12:00:00");
        $b_ts = strtotime("{$b} 12:00:00");

        return ($b - $a) <= (36 * 60 * 60);
    },
LSerni
  • 55,617
  • 10
  • 65
  • 107
  • After converting all my dates to timestamps with strtotime the interval function still prints each day as it's own interval: Array ( [0] => 1403568000..1403568000 [1] => 1403654400..1403654400 [2] => 1403913600..1403913600 [3] => 1404000000..1404000000 ) rather than recognising consecutive days and treating them as one interval. This method works great for numbers but how can I use it for dates? – Ralphonz Jun 24 '14 at 11:06