Search code examples
laravelphp-carbon

Can't figure out how to correctly check if there is an appointment in between times with Carbon and Laravel


This might be much simpler than i think it is, but i've scratched my head around it for a while now. Probably too long, and stuck with the same wrong solutions to get outside my own head. So i could use some help.

I'm constructing an appointment system, and lets say that an appointment is 1 hour long. Between 12-13. I can make sure that no appointments are started during that time. But, my problem is. If i create an appointment and that is 2 hours long. Then, right now someone can book it at 11.30, since it will finish at 13.30. Which obviously shouldn't be possible, because there is an appointment in between.

I will supply my current code below, and hope that some of you, hopefully smarter for me can see, what probably is an easy solution. I have removed all my testcode, since they have not shown any promise.

        $intervals = CarbonInterval::minutes('15')->toPeriod($start, $end);
        foreach ($intervals as $time) {
            $this_time = Carbon::parse($time)->tz('Europe/Stockholm');
            $current_mission_end_from_time = Carbon::parse(roundToNearestMinuteInterval($this_time->addMinutes($current_mission_length)));

            if ($busy_between->isNotEmpty()) {
                foreach ($busy_between as $busy) {
                    if ($time->between($busy['start'], $busy['end'])) {
                        $busy_times->add($time->format('H:i'));
                    }
                }
            }
        }

In the end, all non-possible times will be saved to $busy_times, then i will run this code to show any free times.

            foreach ($intervals as $time) {
                if (!$busy_times->contains($time->format('H:i'))) {
                    $free_times->add($time->format('H:i'));
                }
            }

UPDATE Here is the solution code added to the above, from the correct answer below, if anyone else wonders.

            if ($busy_between->isNotEmpty()) {
                foreach ($busy_between as $busy) {
                    if ($time->between($busy['start'], $busy['end'])) {
                        $busy_times->add($time->format('H:i'));
                    }

                    $exitingAppointment = CarbonPeriod::create($busy['start'], $busy['end']);
                    $appointmentTentative = CarbonPeriod::create($time, $current_mission_end_from_time);

                    if ($exitingAppointment->overlaps($appointmentTentative)) {
                        $busy_times->add($time->format('H:i'));
                    }
                }
            }

Solution

  • Use Carbon\CarbonPeriod::overlaps:

    $exitingAppointment = \Carbon\CarbonPeriod::create('2023-02-26 12:00', '2023-02-26 13:00');
    $appointmentTentative = \Carbon\CarbonPeriod::create('2023-02-26 11:30', '2023-02-26 13:30');
    
    if ($exitingAppointment->overlaps($appointmentTentative)) {
        echo "No: overlaps with existing appointment\n";
    } else {
        echo "All good\n";
    }