Days, weeks and structured data
Day and week views are wall-clock views: they show ranges as defined, with exceptions applied wherever a real date is involved:
use RoundlyConsulting\OpeningHours\Enums\Weekday;
$hours->forDate('2026-12-24')->toString(); // "Closed" or "09:00–12:00" (translated)
$hours->forDate('2026-12-24')->ranges; // list<TimeRange>
$hours->forDate('2026-12-24')->source; // DaySource::Schedule|Exception|Dynamic|None
$hours->isOpenOnDate('2026-12-24');
$hours->isOpenOn('monday'); // regular schedule, exceptions ignored
$hours->forWeekday(Weekday::Monday);
$hours->forWeek()->grouped(); // list<WeekdayGroup>: Mon–Fri · Sat · Sun, each with its hours
$hours->forWeek()->keyed(); // ['monday' => DayHours, …]
$hours->forWeekOf('2026-09-30'); // the seven actual dates, exceptions applied
$hours->forPeriod('2026-12-20', '2026-12-31');
$hours->regularClosingDays(); // list<Weekday>
$hours->toStructuredData()->toJson(); // schema.org OpeningHoursSpecificationisOpenOnDate() checks whether any range starts on that date; isOpenOn() and forWeekday() read the regular schedule and ignore exceptions. A DateTimeInterface passed where a date is expected is converted to the calendar timezone first.
Rendering days and groups
DayHours::toString(rangeSeparator, timeSeparator, locale, closedText) renders a day. Without closedText a closed day reads the translated “Closed” and a single all-day range “Open 24 hours”; any explicit closedText — even '' — gives literal output. forWeek()->grouped() folds identical consecutive days into groups (grouped(false) also merges non-consecutive ones), each with a translated label() such as Mon–Fri:
$day = $hours->forDate('2026-12-24');
$day->toString(); // "09:00–12:00, 13:00–18:00", or the translated "Closed"
$day->toString(',', '-', closedText: ''); // "09:00-12:00,13:00-18:00" — literal, '' when closed
$day->toString(locale: 'sk');
$day->isOpenAllDay();
$day->totalMinutes();
$day->label; // an exception's label, e.g. "Christmas"
foreach ($hours->forWeek()->grouped() as $group) {
echo $group->label().' '.$group->hoursText(); // "Mon–Fri 08:00–17:00"
}Structured data
toStructuredData() emits schema.org OpeningHoursSpecification items for JSON-LD. 24:00 becomes 23:59, overnight ranges keep opens 22:00 / closes 02:00, a seasonal schedule adds validFrom and validThrough, and one-off exceptions within api.upcoming_exceptions_days add dated items (closed days open and close at 00:00):
$hours->toStructuredData()->toJson();
// [{"@type":"OpeningHoursSpecification","dayOfWeek":"https://schema.org/Monday","opens":"09:00","closes":"17:00"}, …]
$jsonLd = [
'@context' => 'https://schema.org',
'@type' => 'MedicalClinic',
'name' => $clinic->name,
'openingHoursSpecification' => $hours->toStructuredData()->toArray(),
];Weekday enum
Weekday is a string-backed enum with parsing, ordering and translation helpers, plus the enums-for-laravel helpers such as toOptions() for select inputs:
use RoundlyConsulting\OpeningHours\Enums\Weekday;
Weekday::fromKey('Mon'); // Weekday::Monday
Weekday::ordered(Weekday::Sunday); // [Sunday, Monday, …, Saturday]
Weekday::Friday->translated('sk'); // localized long name
Weekday::Friday->translated(short: true);
Weekday::Saturday->isWeekend(); // true
Weekday::toOptions(); // value => label map for select inputsTranslations
Weekday names (long and short), “Closed”, “Open 24 hours”, the unavailable reasons and every validation message ship in English and Slovak under the opening-hours namespace. Publish them with the opening-hours-translations tag to reword or add a locale.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.