Pracovné dni a hodiny
Termíny a SLA sa počítajú v otvorenom čase, nie v kalendárnom. addOpenDays() vráti rovnaký miestny čas v n-tý otvorený dátum po dátume začiatku („2 pracovné dni“: piatok 15:00 → utorok 15:00); addOpenTime() vráti okamih po uplynutí zadaného CarbonInterval otvoreného času („4 pracovné hodiny“). Obe preskočia zatvorené dni v týždni, sviatky, výnimky aj dynamické výnimky a obe vracajú CarbonImmutable vo výstupnom časovom pásme kalendára:
use Carbon\CarbonImmutable;
use Carbon\CarbonInterval;
use RoundlyConsulting\OpeningHours\Facades\OpeningHours;
OpeningHours::sync($office, [
'timezone' => 'Europe/Bratislava',
'week' => array_fill_keys(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], ['09:00-17:00']),
'exceptions' => [['date' => '2026-11-09']], // a holiday Monday
]);
OpeningHours::sync($office, ['timezone' => 'Europe/Bratislava', 'week' => ['saturday' => ['10:00-14:00']]], 'weekend');
$friday = CarbonImmutable::parse('2026-11-06 10:00', 'Europe/Bratislava');
// "N business days": the same local time on the n-th open date after the start's date
OpeningHours::addOpenDays($office, $friday, 2); // Wed 2026-11-11 10:00 — the holiday skipped
OpeningHours::addOpenDays($office, $friday, 1, 'weekend'); // Sat 2026-11-07 10:00
// "N business hours": the instant that much open time later
OpeningHours::addOpenTime($office, $friday->setTime(16, 0), CarbonInterval::hours(2)); // Tue 2026-11-10 10:00
OpeningHours::addOpenTime($office, $friday, CarbonInterval::hours(5), 'weekend'); // Sat 2026-11-14 11:00Všetky vstupné body
Fasáda aj injektovaný manažér prijímajú vlastníka a voliteľný kľúč kalendára; dotazovací objekt, trait vlastníka aj akcie spúšťajú ten istý kód — ak hostiteľ v kontajneri previaže AddOpenDaysAction alebo AddOpenTimeAction, platí to za všetkými z nich:
use Carbon\CarbonInterval;
use RoundlyConsulting\OpeningHours\Actions\AddOpenTimeAction;
use RoundlyConsulting\OpeningHours\Facades\OpeningHours;
use RoundlyConsulting\OpeningHours\OpeningHoursManager;
// The query object and the owner trait — shorthand over the same manager:
OpeningHours::for($office)->addOpenDays($friday, 2); // Wed 10:00
$office->addOpenDays($friday, 2); // Wed 10:00
$office->addOpenTime($friday, CarbonInterval::hours(8)); // Tue 10:00
$office->addOpenTime($friday, CarbonInterval::hour(), 'weekend'); // Sat 11:00
// The injected manager and the raw action:
app(OpeningHoursManager::class)->addOpenDays($office, $friday, 2); // Wed 10:00
app(AddOpenTimeAction::class)->execute(OpeningHours::for($office), $friday, CarbonInterval::hours(8)); // Tue 10:00Ako počítajú
- Otvorený dátum je taký, v ktorý začína nejaký rozsah — rovnaké pravidlo ako pri isOpenOnDate() — s uplatnenými výnimkami aj dynamickými výnimkami, takže sviatok sa preskočí a výnimka, ktorá otvorí inak zatvorený deň, sa započíta.
- addOpenDays() počíta otvorené dátumy striktne po miestnom dátume začiatku a zachová čas začiatku podľa miestnych hodín, aj keď je v tom čase zatvorené.
- addOpenTime() spotrebúva len otvorený čas. Obdobia sú polootvorené, takže začiatok presne v čase zatvorenia sa počíta ako zatvorené (pondelok 17:00 + 30 min → utorok 09:30) a nočný rozsah sa spotrebuje aj cez polnoc.
- addOpenTime() počíta celé sekundy intervalu — zlomok sekundy sa zahodí.
- Začiatok môže byť ľubovoľný DateTimeInterface a číta sa v časovom pásme kalendára: piatok 23:30 v New Yorku je v Bratislave už sobota.
- Nula alebo záporná hodnota vráti začiatok bez zmeny, vo výstupnom časovom pásme.
use Carbon\CarbonImmutable;
use Carbon\CarbonInterval;
use RoundlyConsulting\OpeningHours\OpeningHours;
$hours = OpeningHours::make([
'week' => array_fill_keys(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], ['09:00-17:00']),
], 'UTC');
$hours->addOpenTime(CarbonImmutable::parse('2026-11-06 16:00', 'UTC'), CarbonInterval::hours(2)); // Mon 10:00
$hours->addOpenTime(CarbonImmutable::parse('2026-11-09 17:00', 'UTC'), CarbonInterval::minutes(30)); // Tue 09:30 — 17:00 is already closed
$hours->addOpenDays(CarbonImmutable::parse('2026-11-07 10:00', 'UTC'), 2); // Tue 10:00 — Saturday's time kept
$hours->addOpenDays(CarbonImmutable::parse('2026-11-07 10:00', 'UTC'), 0); // Sat 10:00 — zero or less returns the startZmena času
addOpenDays() zachová v cieľový dátum čas začiatku podľa miestnych hodín. Čas, ktorý nastane dvakrát, berie prvý výskyt, ako všade v engine, no čas v medzere pri prechode na letný čas sa posunie dopredu o dĺžku medzery (02:30 → 03:30, tak ako ho rieši PHP), nie na okamih prechodu — termín si tak zachová odstup od začiatku. addOpenTime() počíta skutočne uplynutý otvorený čas, takže 25-hodinový deň pri prechode na zimný čas obsahuje 25 otvorených hodín:
use Carbon\CarbonImmutable;
use Carbon\CarbonInterval;
use RoundlyConsulting\OpeningHours\OpeningHours;
// Europe/Bratislava springs forward on Sunday 2026-03-29 and falls back on Sunday 2026-10-25
$sundays = OpeningHours::make(['week' => ['sunday' => ['00:00-24:00']]], 'Europe/Bratislava');
$sundays->addOpenDays(CarbonImmutable::parse('2026-03-22 02:30', 'Europe/Bratislava'), 1);
// 2026-03-29 03:30 — 02:30 does not exist that day, so it moves forward by the gap
$sundays->addOpenDays(CarbonImmutable::parse('2026-10-18 02:30', 'Europe/Bratislava'), 1);
// 2026-10-25 02:30 +02:00 — 02:30 happens twice; the first occurrence
$sundays->addOpenTime(CarbonImmutable::parse('2026-10-25 00:00', 'Europe/Bratislava'), CarbonInterval::hours(24));
// 2026-10-25 23:00 — the day holds 25 real open hoursOkno hľadania
Ani jedna metóda nehľadá donekonečna. Odpoveď musí padnúť do opening-hours.search_days miestnych dní od dátumu začiatku — celé obdobie, nie medzera medzi otvorenými dňami. Kalendár, ktorý nie je nikdy otvorený, vlastník bez kalendára alebo obdobie dlhšie než okno vyhodí OpenTimeNotFoundException s hodnotou searchDays:
use RoundlyConsulting\OpeningHours\Exceptions\OpenTimeNotFoundException;
use RoundlyConsulting\OpeningHours\Facades\OpeningHours;
try {
$due = OpeningHours::addOpenDays($office, now(), 2);
} catch (OpenTimeNotFoundException $e) {
// The calendar has not enough open time within 366 days of the start (opening-hours.search_days).
// $e->searchDays === 366
}Pod OpeningHours::fake() obe metódy naďalej odpovedajú z databázy a nič nezaznamenajú — ide o čítanie.
Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.