Ad

Dynamic Timeslots With One Hour Intervals And Dynamic Intervals Too

- 1 answer

I have a checkin time and checkout time, I already have the code for the dynamic timeslots but I am struggling with the dynamic intervals. Code below -

$attendance = Attendance::where('user_id', '=', $request->user()->id)->latest()->first();
if(!is_null($attendance) && !is_null($attendance->checkout)){
    $created = (string) $attendance->created_at;
    $timing = array($created);
    $main_diff = Carbon::parse($created)->diffInSeconds($attendance->checkout, false);

    $modul = $main_diff % 3600;
    $main_amount = $main_diff - $modul;
    $count = $main_amount/3600;

    if($count > 1){
        for($x=0; $x <= count($timing); $x++){
            $diff = Carbon::parse($timing[$x])->diffInSeconds($attendance->checkout, false);
            if($diff > 0){
                if($x==0){
                    array_push($timing, (string) Carbon::parse($timing[$x])->minute(0)->second(0)->addHour());
                }
                elseif($x>0 and $x<$count){
                    $var = Carbon::parse($timing[$x]);
                    array_push($timing, (string) $var->addHour());
                }
                elseif($x == $count){
                    array_push($timing, (string) $attendance->checkout);
                }
            }
            else{
                break;
            }
        }

        $timings = [];
        $last;
        foreach($timing as $edit){
            if(isset($last)){
                $timings[] = $last.' - '.Carbon::parse($edit)->format('h:i');
            }
            $last = Carbon::parse($edit)->format('h:i');
        }
        $variable['data'] = $timings;
        return response(json_encode($variable), 200);
    }
}

Output of the above code -

10:15-11:00
11:00-12:00
12:00-12:18

Now there are two different events EventFirst, EventSecond - What I want is to integrate the timings of the events in the main timings. For Example -

10:15 - 11:00
11:00 - EventFirst->start_time
EventFirst->start_time - EventFirst->end_time
EventFirst->end_time - Next Nearest Hour
Next Nearest Hour - EventSecond->start_time
EventSecond->start_time - EventSecond->end_time
EventSecond->end_time - Next Nearest Hour
Next Nearest Hour - Checkout Time 

The problem is that the event is not a instance it is a collection retrieved from database. So what I have to do is first take all the timings from the events in an array and check on every iteration.

I don't know man, my brain is cooked.


Better Explanation

I have three tables, namely -

Attendance, Event One, Event Two

Now The relevant columns in each table -

Attendance

|____checkout_time (Carbon Timestamp)

|____created_at (Carbon Timestamp)

Event One

|____event_start (Carbon Timestamp)

|____event_duration (Int (Seconds))

Event Two

|____event_time (Carbon Timestamp)

|____event_end_time (Carbon Timestamp)

Now what the main requirement is, That based on the Attendance table there should be hourly intervals except for the checkin and checkout time, So the format should be -

checkin - Next Nearest Hour (e.g - 10:15-11:00)
Last Hour - Next Hour (e.g 11:00-12:00, 12:00-13:00, etc)
Nearest Hour Before Checkout - checkout (e.g - 18:00-18:22) 

The above output has been acheived.

Now the problem arises when I have to add the timeslots from the other two events, in the main time slots.

So the format now becomes -

checkin - Nearest Hour (e.g 11:34 - 12:00)
(Assuming Event one exists)
(case 1) -
If eventOne start and end is between Nearest Hour and the Next Hour add it in between
(e.g - 12:00-12:06, **12:06-12:54**, 12:54-13:00) 
(case 2) - 
If eventOne end crosses the Next Hour, unset the normal interval
(e.g - 12:00-12:06, **12:06-13:28**, 13:28-14:00)
Same Goes for eventTwo

Now is everything clear?

Ad

Answer

I would start by the adding the slots for the events first. Then checking, then checkout. And, only at the end, compute the hourly slots.

I haven't done the hourly slots, that you've already done.

Here's an example.

But it still needs some checks for edge cases like dates (events, checkin, checkout) that are hourly (eg: 11:00)

class ComputeTimeSlots {
    /** @var Carbon */
    public $checkin;
    /** @var Carbon */
    public $checkout;
    /** @var \Illuminate\Support\Collection */
    public $events;
    /** @var \Illuminate\Support\Collection */
    public $slots;

    /**
     * ComputeTimeSlots constructor.
     * @param $checkin
     * @param $checkout
     * @param \Illuminate\Support\Collection $events
     */
    public function __construct(Carbon $checkin, Carbon $checkout, Collection $events)
    {
        $this->checkin = $checkin;
        $this->checkout = $checkout;
        $this->events = $events;
        $this->slots = collect();
    }

    public function handle()
    {
        // First the Events
        foreach ($this->events as $event) {
            /** @var EEvent $event */
            $this->slots->push(
                new Slot($event->start, $event->end)
            );
        }

        // Then Checking
        /** @var Carbon $earliest_event_start_date */
        $earliest_event_start_date = $this->events->pluck('start')->sort()->first();
        $hourAfterCheckin = $this->checkin->clone()->setMinute(0)->addHour();

        if($hourAfterCheckin < $earliest_event_start_date) {
            $this->slots->push(
                new Slot($this->checkin, $hourAfterCheckin)
            );
        } else {
            $this->slots->push(
                new Slot($this->checkin, $earliest_event_start_date)
            );
            $hourAfterEvent = $earliest_event_start_date->clone()->setMinute(0)->addHour();
            $this->slots->push(
                new Slot($earliest_event_start_date, $hourAfterEvent)
            );
        }

        // Then Checkout
        /** @var Carbon $earliest_event_start_date */
        $last_event_end_date = $this->events->pluck('end')->sort()->last();
        $hourBeforeCheckout = $this->checkout->clone()->setMinute(0);

        if($hourBeforeCheckout > $last_event_end_date) {
            $this->slots->push(
                new Slot($hourBeforeCheckout, $this->checkout)
            );
        } else {
            $this->slots->push(
                new Slot($last_event_end_date, $this->checkout)
            );
            $hourBeforeEvent = $last_event_end_date->clone()->setMinute(0);
            $this->slots->push(
                new Slot($hourBeforeEvent, $last_event_end_date)
            );
        }
        $this->slots = $this->slots->sortBy('start');

        // Then compute hourly intervals

        return $this;
    }
}

class Slot {
    /** @var \Carbon\Carbon */
    public $start;
    /** @var \Carbon\Carbon */
    public $end;

    /**
     * Slot constructor.
     * @param \Carbon\Carbon $start
     * @param \Carbon\Carbon $end
     */
    public function __construct(Carbon $start, Carbon $end)
    {
        $this->start = $start;
        $this->end = $end;
    }

    public function toArray()
    {
        return "{$this->start->format('H:i')}-{$this->end->format('H:i')}";
    }
}

class EEvent extends Slot{}

Example:

$c1 = new ComputeTimeSlots(
    Carbon::parse('10:15'),
    Carbon::parse('18:22'),
    collect([
        new EEvent(Carbon::parse('12:06'), Carbon::parse('12:54')),
        new EEvent(Carbon::parse('13:06'), Carbon::parse('14:30'))
    ])
);

var_dump($c1->handle()->slots->map->toArray()->all());

Will output:

enter image description here

Ad
source: stackoverflow.com
Ad