NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages

No routes or controllers ship — the endpoints are yours. Four JSON resources cover the common outputs:

use RoundlyConsulting\OpeningHours\Facades\OpeningHours;
use RoundlyConsulting\OpeningHours\Http\Resources\CalendarResource;
use RoundlyConsulting\OpeningHours\Http\Resources\DayHoursResource;
use RoundlyConsulting\OpeningHours\Http\Resources\OpeningStatusResource;
use RoundlyConsulting\OpeningHours\Http\Resources\SlotResource;

return OpeningStatusResource::make(OpeningHours::for($clinic));         // status (optionally ->at($instant))
return CalendarResource::make(OpeningHours::calendar($clinic));         // editable definition
return DayHoursResource::collection(OpeningHours::for($clinic)->forWeekOf(now()));
return SlotResource::collection($slots);

Status shape

OpeningStatusResource returns timezone, at, is_open, current_period, next_open, next_close, today, week (7 days) and upcoming_exceptions. Instants are ISO-8601 with offset; only weekday_label and text are translated (app locale):

{
  "timezone": "Europe/Bratislava",
  "at": "2026-09-26T12:00:00+02:00",
  "is_open": true,
  "current_period": {"start": "2026-09-26T09:00:00+02:00", "end": "2026-09-26T14:00:00+02:00",
                     "label": null, "start_unbounded": false, "end_unbounded": false},
  "next_open": "2026-09-28T08:00:00+02:00",
  "next_close": "2026-09-26T14:00:00+02:00",
  "today": {"date": "2026-09-26", "weekday": "saturday", "weekday_label": "Saturday", "closed": false,
            "all_day": false, "source": "schedule", "label": null,
            "ranges": [{"from": "09:00", "to": "14:00", "label": null, "capacity": null}], "text": "09:00–14:00"},
  "week": [ /* 7 day objects */ ],
  "upcoming_exceptions": [ {"date": "2026-12-24", "closed": true, "label": "Christmas", "ranges": []} ]
}

week lists the next seven dates (api.week_mode = upcoming) or the calendar week from first_day_of_week (calendar_week). next_open and next_close are null when nothing is found within search_days.

Editable definitions

CalendarResource returns the canonical input plus id, key, revision and updated_at. It can be submitted back to OpeningHours::sync() unchanged — send revision as expectedRevision to guard concurrent edits:

// GET — the editable definition, including its revision
return CalendarResource::make(OpeningHours::calendar($clinic));

// PUT — submit it back (edited or unchanged); the revision guards concurrent edits
OpeningHours::sync(
    $clinic,
    $request->validated('opening_hours'),
    expectedRevision: $request->integer('revision'),
);

// Status as of a given instant instead of now
return OpeningStatusResource::make(OpeningHours::for($clinic))->at($instant);

meta appears only with api.expose_meta — and a definition resubmitted without meta clears it.

Day and slot shapes

  • DayHoursResource — date, weekday, weekday_label, closed, all_day, source, label, ranges and text (plus meta when exposed).
  • SlotResource — start, end, available, remaining_capacity and reason.

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 crypto

By 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.