Laravel Zap logo
Guides

Schedule Patterns

Learn how to define recurring schedules and time periods.

Schedule Patterns

Recurrence

Zap supports flexible recurrence patterns with extended frequencies.

$schedule = Zap::for($doctor)
    ->named('Office Hours')
    ->availability();

// Daily
$schedule->daily()
    ->from('2025-01-01')
    ->to('2025-12-31');

// Weekly (specific days)
$schedule->weekly(['monday', 'wednesday', 'friday'])->forYear(2025);

// Weekly with time period (convenience method)
// Combines weekly() and addPeriod() in a single call
$schedule->weekDays(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], '09:00', '17:00')
    ->forYear(2025);

// The weekDays() method is equivalent to:
// $schedule->weekly(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
//     ->addPeriod('09:00', '17:00')
//     ->forYear(2025);

// Weekly odd (specific days) – runs only on odd-numbered ISO weeks
$schedule->weeklyOdd(['monday', 'wednesday', 'friday'])->forYear(2025);

// Weekly odd with time period (convenience method)
// Combines weeklyOdd() and addPeriod() in a single call
$schedule->weekOddDays(['monday', 'wednesday', 'friday'], '09:00', '17:00')
    ->forYear(2025);

// Weekly even (specific days) – runs only on even-numbered ISO weeks
$schedule->weeklyEven(['monday', 'wednesday', 'friday'])->forYear(2025);

// Weekly even with time period (convenience method)
// Combines weeklyEven() and addPeriod() in a single call
$schedule->weekEvenDays(['monday', 'wednesday', 'friday'], '09:00', '17:00')
    ->forYear(2025);

// Bi-weekly (week of the start date by default, optional anchor)
$schedule->biweekly(['tuesday', 'thursday'])
    ->from('2025-01-07')
    ->to('2025-03-31');

// Monthly (supports multiple days)
$schedule->monthly(['days_of_month' => [1, 15]])->forYear(2025);

// Bi-monthly (multiple days, optional start_month anchor)
$schedule->bimonthly(['days_of_month' => [5, 20], 'start_month' => 2])
    ->from('2025-01-05')
    ->to('2025-06-30');

// Quarterly (multiple days, optional start_month anchor)
$schedule->quarterly(['days_of_month' => [7, 21], 'start_month' => 2])
    ->from('2025-02-15')
    ->to('2025-11-15');

// Semi-annually (multiple days, optional start_month anchor)
$schedule->semiannually(['days_of_month' => [10], 'start_month' => 3])
    ->from('2025-03-10')
    ->to('2025-12-10');

// Annually (multiple days, optional start_month anchor)
$schedule->annually(['days_of_month' => [1, 15], 'start_month' => 4])
    ->from('2025-04-01')
    ->to('2026-04-01');

Using weekDays() for Office Hours

The weekDays() method is particularly useful for common scenarios like office hours or regular shift schedules. It combines weekly recurrence with a single time period:

// Using weekDays() - combines weekly() and addPeriod()
Zap::for($doctor)
    ->named('Office Hours')
    ->availability()
    ->weekDays(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], '09:00', '17:00')
    ->forYear(2025)
    ->save();

// Equivalent to:
Zap::for($doctor)
    ->named('Office Hours')
    ->availability()
    ->weekly(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
    ->addPeriod('09:00', '17:00')
    ->forYear(2025)
    ->save();
Use weekDays() when you have a single time period for specific weekdays. For multiple time periods (e.g., split shifts), use weekly() with multiple addPeriod() calls instead.

Weekly Odd/Even Scheduling

Weekly odd and even scheduling is useful for alternating schedules, such as shared resources or rotating shifts:

// Weekly odd - runs only on odd-numbered ISO weeks
Zap::for($employee)
    ->named('Morning Shift - Odd Weeks')
    ->availability()
    ->weeklyOdd(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
    ->addPeriod('05:00', '13:00')
    ->forYear(2025)
    ->save();

// Weekly even - runs only on even-numbered ISO weeks
Zap::for($employee)
    ->named('Afternoon Shift - Even Weeks')
    ->availability()
    ->weeklyEven(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
    ->addPeriod('13:00', '21:00')
    ->forYear(2025)
    ->save();

Using weekOddDays() and weekEvenDays()

Similar to weekDays(), these convenience methods combine odd/even weekly recurrence with a single time period:

// Using weekOddDays() - combines weeklyOdd() and addPeriod()
Zap::for($employee)
    ->named('Morning Shift - Odd Weeks')
    ->availability()
    ->weekOddDays(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], '05:00', '13:00')
    ->forYear(2025)
    ->save();

// Using weekEvenDays() - combines weeklyEven() and addPeriod()
Zap::for($employee)
    ->named('Afternoon Shift - Even Weeks')
    ->availability()
    ->weekEvenDays(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], '13:00', '21:00')
    ->forYear(2025)
    ->save();
Weekly odd/even scheduling uses ISO week numbers. Week 1 is the first week of the year that contains a Thursday. This ensures consistent behavior across different calendar systems.

Date Ranges

Define the validity period of a schedule.

$schedule = Zap::for($doctor)
    ->named('Office Hours')
    ->availability();

// Single date
$schedule->from('2025-01-15');

// Alternative: on() is an alias for from()
$schedule->on('2025-01-15');

// Date range
$schedule->from('2025-01-01')->to('2025-12-31');

// Alternative syntax
$schedule->between('2025-01-01', '2025-12-31');

// Entire year shortcut
$schedule->forYear(2025);

Time Periods

Define the time slots within a day.

$schedule = Zap::for($doctor)
    ->named('Office Hours')
    ->availability();

// Single period
$schedule->addPeriod('09:00', '17:00');

// Multiple periods (split shifts)
$schedule->addPeriod('09:00', '12:00');
$schedule->addPeriod('14:00', '17:00');