Fix timezone bug causing slots past closing time; remove lunch fallback outside window
- Add Europe/Oslo timezone to all DateTime constructors in getAvailableTimes() and computeLunchBreak() to prevent UTC vs local time mismatch that allowed booking slots 1 hour past the worker's end time on same-day bookings - Remove fallback loop in computeLunchBreak() that pushed the lunch break outside the configured window; lunch break is now strictly enforced within the interval Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -439,17 +439,17 @@ class Service_model extends CI_Model {
|
||||
|
||||
if ($override->is_day_off) return [];
|
||||
|
||||
$dayStartTime = new DateTime($selectedDate.' '.$override->start_time);
|
||||
$finishTime = new DateTime($selectedDate.' '.$override->end_time);
|
||||
$dayStartTime = new DateTime($selectedDate.' '.$override->start_time, new DateTimeZone('Europe/Oslo'));
|
||||
$finishTime = new DateTime($selectedDate.' '.$override->end_time, new DateTimeZone('Europe/Oslo'));
|
||||
} else {
|
||||
$weekday = date('w', strtotime($selectedDate)); // 0 = Sunday, 6 = Saturday
|
||||
$weekNumber = date('W', strtotime($selectedDate));
|
||||
$isOddWeek = $weekNumber % 2 !== 0;
|
||||
|
||||
$scheduleQuery = $this->db->query("
|
||||
SELECT * FROM worker_schedule
|
||||
WHERE worker_id = '{$worker_id}'
|
||||
AND weekday = '{$weekday}'
|
||||
SELECT * FROM worker_schedule
|
||||
WHERE worker_id = '{$worker_id}'
|
||||
AND weekday = '{$weekday}'
|
||||
AND (
|
||||
is_alternate_week = 0
|
||||
OR (is_alternate_week = 1 AND " . ($isOddWeek ? "1" : "0") . ")
|
||||
@@ -461,8 +461,8 @@ class Service_model extends CI_Model {
|
||||
}
|
||||
|
||||
$schedule = $scheduleQuery->row();
|
||||
$dayStartTime = new DateTime($selectedDate . ' ' . $schedule->start_time);
|
||||
$finishTime = new DateTime($selectedDate . ' ' . $schedule->end_time);
|
||||
$dayStartTime = new DateTime($selectedDate . ' ' . $schedule->start_time, new DateTimeZone('Europe/Oslo'));
|
||||
$finishTime = new DateTime($selectedDate . ' ' . $schedule->end_time, new DateTimeZone('Europe/Oslo'));
|
||||
}
|
||||
|
||||
// --- ÚJ: ma foglalva csak (következő 15 perces blokk + 1 óra) UTÁN legyen időpont ---
|
||||
@@ -685,8 +685,9 @@ class Service_model extends CI_Model {
|
||||
|
||||
$lunchDuration = new DateInterval('PT30M');
|
||||
$lunchStep = new DateInterval('PT15M');
|
||||
$winStartDt = new DateTime($date . ' ' . $winStart);
|
||||
$winEndDt = new DateTime($date . ' ' . $winEnd);
|
||||
$tz = new DateTimeZone('Europe/Oslo');
|
||||
$winStartDt = new DateTime($date . ' ' . $winStart, $tz);
|
||||
$winEndDt = new DateTime($date . ' ' . $winEnd, $tz);
|
||||
|
||||
// Clamp window to actual shift hours
|
||||
if ($shiftStart && $winStartDt < $shiftStart) $winStartDt = clone $shiftStart;
|
||||
@@ -695,10 +696,11 @@ class Service_model extends CI_Model {
|
||||
$scanEnd = (clone $winEndDt)->sub($lunchDuration);
|
||||
|
||||
$isFree = function($candidate) use ($lunchDuration, $dayBookings, $date) {
|
||||
$tz = new DateTimeZone('Europe/Oslo');
|
||||
$candEnd = (clone $candidate)->add($lunchDuration);
|
||||
foreach ($dayBookings as $bk) {
|
||||
$bkS = new DateTime($date . ' ' . $bk->booking_start_time);
|
||||
$bkE = new DateTime($date . ' ' . $bk->booking_finish_time);
|
||||
$bkS = new DateTime($date . ' ' . $bk->booking_start_time, $tz);
|
||||
$bkE = new DateTime($date . ' ' . $bk->booking_finish_time, $tz);
|
||||
if ($bkS < $candEnd && $bkE > $candidate) return false;
|
||||
}
|
||||
return true;
|
||||
@@ -713,7 +715,7 @@ class Service_model extends CI_Model {
|
||||
if (!empty($freeSlots)) {
|
||||
// Pick the slot closest to preferred time (or start of window if no preference)
|
||||
$prefDt = $preferredTime
|
||||
? new DateTime($date . ' ' . $preferredTime)
|
||||
? new DateTime($date . ' ' . $preferredTime, new DateTimeZone('Europe/Oslo'))
|
||||
: clone $winStartDt;
|
||||
$best = null;
|
||||
$bestDiff = PHP_INT_MAX;
|
||||
@@ -725,12 +727,6 @@ class Service_model extends CI_Model {
|
||||
return ['start' => $best->format('H:i'), 'end' => $bestEnd->format('H:i')];
|
||||
}
|
||||
|
||||
// Fallback: search after the window
|
||||
for ($c = clone $winEndDt; ; $c->add($lunchStep)) {
|
||||
$candEnd = (clone $c)->add($lunchDuration);
|
||||
if ($candEnd > $shiftEnd) break;
|
||||
if ($isFree($c)) return ['start' => $c->format('H:i'), 'end' => $candEnd->format('H:i')];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user