Schedule Evaluation
evaluateSchedule function: check if the current time matches a schedule config with date ranges, time windows, and blackouts
Schedule Evaluation
The main entry points for determining if a schedule is currently active.
checkSchedule
Simple boolean check if a schedule is active.
Usage
import { checkSchedule } from '@tour-kit/scheduling'
const schedule = {
daysOfWeek: [1, 2, 3, 4, 5],
timeOfDay: { start: '09:00', end: '17:00' },
}
const isActive = checkSchedule(schedule)
// true or falseAPI
function checkSchedule(
schedule: Schedule,
options?: ScheduleEvaluationOptions
): booleanParameters
- schedule - The schedule configuration to evaluate
- options - Optional evaluation options:
interface ScheduleEvaluationOptions { /** Override the current date/time for testing */ now?: Date /** User's detected timezone */ userTimezone?: string }
Returns
true if the schedule is active, false otherwise.
Examples
// Basic check
if (checkSchedule(schedule)) {
showTour()
}
// Override time for testing
const isActive = checkSchedule(schedule, {
now: new Date('2024-02-15T10:00:00Z'),
userTimezone: 'America/New_York',
})
// Check multiple schedules
const schedules = [schedule1, schedule2, schedule3]
const anyActive = schedules.some((s) => checkSchedule(s))isScheduleActive
Returns a result object with the active status and reason for being inactive.
Usage
import { isScheduleActive } from '@tour-kit/scheduling'
const { isActive, reason } = isScheduleActive(schedule)
if (!isActive) {
console.log('Inactive reason:', reason)
// 'disabled' | 'not_started' | 'ended' | 'wrong_day' | etc.
}API
function isScheduleActive(
schedule: Schedule,
options?: ScheduleEvaluationOptions
): ScheduleResultReturns
interface ScheduleResult {
/** Whether the schedule is currently active */
isActive: boolean
/** Quick reason code if inactive */
reason?: ScheduleInactiveReason
}
type ScheduleInactiveReason =
| 'disabled'
| 'not_started'
| 'ended'
| 'wrong_day'
| 'wrong_time'
| 'blackout'
| 'outside_business_hours'
| 'recurring_mismatch'Examples
// Get reason for debugging
const { isActive, reason } = isScheduleActive(schedule)
if (!isActive) {
switch (reason) {
case 'not_started':
console.log('Tour has not started yet')
break
case 'wrong_day':
console.log('Tour only available on weekdays')
break
case 'blackout':
console.log('Tour blocked during blackout period')
break
}
}
// Log analytics
const result = isScheduleActive(schedule)
analytics.track('schedule_evaluated', {
isActive: result.isActive,
reason: result.reason,
})getScheduleStatus
Returns detailed status information including next active/inactive times and human-readable messages.
Usage
import { getScheduleStatus } from '@tour-kit/scheduling'
const status = getScheduleStatus(schedule)
console.log(status.message)
// "Currently active" or "Outside time range (9:00 AM - 5:00 PM)"
if (status.nextActiveAt) {
console.log('Next active:', status.nextActiveAt)
}API
function getScheduleStatus(
schedule: Schedule,
options?: ScheduleEvaluationOptions & { debug?: boolean }
): ScheduleStatusReturns
interface ScheduleStatus {
/** Whether the schedule is currently active */
isActive: boolean
/** Reason for being inactive */
reason?: ScheduleInactiveReason
/** Human-readable explanation */
message?: string
/** When the schedule will next become active */
nextActiveAt?: Date
/** When the schedule will next become inactive */
nextInactiveAt?: Date
/** Current blackout period if in one */
currentBlackout?: {
id: string
reason?: string
endsAt: Date
}
/** Debug information */
debug?: {
evaluatedAt: Date
timezone: string
localTime: string
dayOfWeek: number
}
}Examples
// Get full status
const status = getScheduleStatus(schedule)
if (status.isActive) {
console.log('Active until:', status.nextInactiveAt)
} else {
console.log(status.message)
console.log('Available again:', status.nextActiveAt)
}
// Debug mode
const status = getScheduleStatus(schedule, { debug: true })
console.log('Evaluated at:', status.debug?.evaluatedAt)
console.log('Timezone:', status.debug?.timezone)
console.log('Local time:', status.debug?.localTime)Evaluation Order
Schedules are evaluated in this specific order. The first check that fails determines the inactive reason:
-
Enabled check - Is
enabledexplicitly set tofalse?- Reason:
'disabled'
- Reason:
-
Date range - Is current date between
startAtandendAt?- Reasons:
'not_started'or'ended'
- Reasons:
-
Blackout periods - Is current time in any blackout period?
- Reason:
'blackout'
- Reason:
-
Day of week - Is today in the
daysOfWeekarray?- Reason:
'wrong_day'
- Reason:
-
Time of day - Is current time within
timeOfDayrange?- Reason:
'wrong_time'
- Reason:
-
Business hours - Is current time within business hours (if configured)?
- Reason:
'outside_business_hours'
- Reason:
-
Recurring pattern - Does current date match the
recurringpattern?- Reason:
'recurring_mismatch'
- Reason:
If all checks pass, the schedule is active.
Why This Order?
The evaluation order is designed to fail fast and provide the most relevant reason:
- Disabled first - No point checking anything else
- Date range early - Broad time constraints before specific ones
- Blackouts override - Important exceptions should block quickly
- Day before time - Day is less granular than time
- Recurring last - Most complex calculation
Testing Schedules
Override the current time to test different scenarios:
import { isScheduleActive } from '@tour-kit/scheduling'
import { describe, it, expect } from 'vitest'
describe('Onboarding Tour Schedule', () => {
const schedule = {
startAt: '2024-01-15',
endAt: '2024-03-31',
daysOfWeek: [1, 2, 3, 4, 5],
timeOfDay: { start: '09:00', end: '17:00' },
}
it('should be active on weekday during business hours', () => {
const result = isScheduleActive(schedule, {
now: new Date('2024-02-14T14:00:00Z'), // Wednesday 2pm
userTimezone: 'UTC',
})
expect(result.isActive).toBe(true)
})
it('should be inactive before start date', () => {
const result = isScheduleActive(schedule, {
now: new Date('2024-01-10T14:00:00Z'),
userTimezone: 'UTC',
})
expect(result.isActive).toBe(false)
expect(result.reason).toBe('not_started')
})
it('should be inactive on weekends', () => {
const result = isScheduleActive(schedule, {
now: new Date('2024-02-10T14:00:00Z'), // Saturday
userTimezone: 'UTC',
})
expect(result.isActive).toBe(false)
expect(result.reason).toBe('wrong_day')
})
it('should be inactive outside time range', () => {
const result = isScheduleActive(schedule, {
now: new Date('2024-02-14T20:00:00Z'), // Wednesday 8pm
userTimezone: 'UTC',
})
expect(result.isActive).toBe(false)
expect(result.reason).toBe('wrong_time')
})
})Performance Considerations
checkScheduleis the fastest (just returns boolean)isScheduleActiveadds minimal overhead for reason trackinggetScheduleStatusis the most expensive (calculates next times)
Choose based on your needs:
// Fast check in hot path
if (checkSchedule(schedule)) {
// Do something
}
// Get reason for logging
const { isActive, reason } = isScheduleActive(schedule)
logEvent('schedule_check', { isActive, reason })
// Full status for UI display
const status = getScheduleStatus(schedule)
return <div>{status.message}</div>Related
- useSchedule - React hook wrapper
- Schedule type - Schedule configuration
- ScheduleStatus type - Status return type