Skip to content

Instantly share code, notes, and snippets.

@renalpha
Last active March 30, 2020 15:50
Show Gist options
  • Save renalpha/ae5b5187516c43ff987bbec561095136 to your computer and use it in GitHub Desktop.
Save renalpha/ae5b5187516c43ff987bbec561095136 to your computer and use it in GitHub Desktop.
Get a group of dates and group them by X minutes (timetables)
<?php
namespace App\Services;
use ArrayIterator;
use Carbon\Carbon;
use Illuminate\Support\Collection;
class TimeService
{
/** @var int */
public const GROUP_BY_MINUTES = 30;
/** @var array */
protected $timesArray = [];
/** @var */
protected $times;
/** @var string */
protected $dateFormat = 'N';
/**
* @param \Illuminate\Support\Collection $times
* @param string $format
* @return array
*/
public function groupTimes(Collection $times, string $format = 'H:i'): array
{
$groups = $times->groupBy(function (Carbon $obj, $key) {
return $obj->format($this->dateFormat);
});
/** @var \Illuminate\Support\Collection $groupTimes */
foreach ($groups as $groupTimes) {
$groupTimes = $groupTimes->sortBy(function (Carbon $obj, $key) {
return Carbon::parse($obj->getTimestamp())->timestamp;
});
$this->times = $groupTimes;
$iterator = $groupTimes->getIterator();
$i = 0;
while ($this->times->count() > 0) {
$time = $iterator->current();
$date = $time->format($this->dateFormat);
$newTime = $time->format($format);
$this->timesArray[$date][$i][] = $newTime;
$this->times->forget($iterator->key());
$this->nextTime($iterator, $i, $format);
}
}
return $this->timesArray;
}
/**
* @param \ArrayIterator $iterator
* @param int $i
* @param string $format
*/
public function nextTime(ArrayIterator $iterator, int $i, string $format): void
{
$time = $iterator->current();
$iterator->next();
$nextTime = $iterator->current();
$date = $time->format($this->dateFormat);
// Create new group
if (!now()->parse($time)->addMinutes(self::GROUP_BY_MINUTES)->eq($nextTime)) {
$i++;
}
$newTime = $nextTime->format($format);
$this->timesArray[$date][$i][] = $newTime;
$this->times->forget($iterator->key());
while ($this->times->count() > 0 && $iterator->valid()) {
$this->nextTime($iterator, $i, $format);
$i++;
}
}
}
<?php
namespace Tests\Unit;
use App\Services\TimeService;
use Tests\TestCase;
class TimeServiceTest extends TestCase
{
/** @test */
public function make_time_range(): void
{
$times = collect([
now()->parse(now()->format('Y-m-d') . '14:30'),
now()->parse(now()->format('Y-m-d') . '09:00'),
now()->parse(now()->format('Y-m-d') . '09:30'),
now()->parse(now()->format('Y-m-d') . '10:00'),
now()->parse(now()->format('Y-m-d') . '12:00'),
now()->parse(now()->format('Y-m-d') . '13:00'),
now()->parse(now()->format('Y-m-d') . '13:30'),
now()->parse(now()->format('Y-m-d') . '15:00'),
now()->parse(now()->format('Y-m-d') . '15:30'),
now()->parse(now()->format('Y-m-d') . '16:00'),
]);
/** @var \App\Services\TimeService $timeService */
$timeService = app(TimeService::class);
$this->assertEquals($timeService->groupTimes($times), [
0 => [
0 => '09:00',
1 => '09:30',
2 => '10:00',
],
1 => [
0 => '12:00',
],
2 => [
0 => '13:00',
1 => '13:30',
],
3 => [
0 => '14:30',
1 => '15:00',
2 => '15:30',
3 => '16:00',
],
]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment