Sorin Haidau
Sorin Haidau

Reputation: 729

Consolidate array of times into compacted ranges of time if contiguous

I have a list of hours which I need to group into simplified contiguous chunks.

$array = [
    [
        "08:30",
        "09:00",
        "09:30",
        "10:00",
        "14:30",
        "15:00",
        "15:30",
        "16:00",
        "16:30"
    ],
    [
        "13:30",
        "14:00",
        "14:30",
        "18:00",
        "18:30",
        "19:00"
    ]
];

and I'm trying to transform them to this format:

[
    [
        ['08:30', '10:00'],
        ['14:30', '16:30']
    ],
    [
        ['13:30', '14:30'],
        ['18:00', '19:00']
    ]
]

I need this for a jQuery plugin is using (Day Schedule Selector).

If the time difference is :30 minutes or less, then compact the times into a group.

Here is what I've tried:

$prepared = '';
foreach ($serialized as $day => $hours) {
    $prepared_hours = array();
    foreach ($hours as $hour) {
        $prepared_hours[] = "['" . $hour . "']"; 
    }
    $prepared .= "'{$day}' : [". implode(',', $prepared_hours) . "],\n";
}

But the result was:

'0' : [['08:30'],['09:00'],['09:30'],['10:00'],['14:30'],['15:00']‌​,['15:30'],['16:00']‌​,['16:30']], 
'1' : [['13:30'],['14:00'],['14:30'],['18:00'],['18:30'],['19:00']

Upvotes: 0

Views: 134

Answers (2)

mickmackusa
mickmackusa

Reputation: 47894

While looping, keep track of the previously iterated time and compare that against the currently iterated time.

When starting a new group, destroy the previously created reference (if there is one yet), then declare a new reference and push it into the result array.

While working with contiguous times, push the current time into the second element of the reference variable specifically.

Code: (Demo)

function compactTimes(
    array $times,
    string $format = 'H:i',
    string $separation = "30 minutes"
): array {
    $result = [];
    $prev = null;
    foreach ($times as $time) {
        if (!$prev || $time !== date("H:i", strtotime("+$separation $prev"))) {
            unset($ref);
            $ref = [$time, $time];
            $result[] =& $ref;
        } else {
            $ref[1] = $time;
        }
        $prev = $time;
    }
    return $result;
}

var_export(
    array_map('compactTimes', $array)
);

Upvotes: 2

rauwebieten
rauwebieten

Reputation: 149

Maybe this gets you started:

$start = new \DateTime('9:00');
$end = new \DateTime('14:00');
$period = new \DatePeriod($start,new \DateInterval('PT30M'),$end);

foreach ($period as $date) {
    print $date->format('H:i') . '<br>';
}

Upvotes: -1

Related Questions