@empellio/business-hours
v0.1.0
Published
A lightweight and accurate TypeScript library for handling business opening hours. Supports multiple daily time slots, holidays, exceptions, overnight openings, and timezone-aware calculations.
Maintainers
Readme
@empellio/business-hours
A lightweight and accurate TypeScript library for handling business opening hours. Supports multiple daily time slots, holidays, exceptions, overnight openings, and timezone-aware calculations. Runs in both Node.js and the browser. Perfect for scheduling, booking systems, e-commerce stores, and any application that needs to determine "open/closed" status and calculate time until next opening or closing.
Installation
npm install @empellio/business-hours luxon
# or
yarn add @empellio/business-hours luxonQuick start
import { createBusinessHours } from '@empellio/business-hours'
const bh = createBusinessHours({
timezone: 'Europe/Prague',
week: {
mon: [{ open: '09:00', close: '12:00' }, { open: '13:00', close: '17:00' }],
tue: [{ open: '09:00', close: '17:00' }],
wed: 'closed',
thu: [{ open: '09:00', close: '17:00' }],
fri: [{ open: '09:00', close: '15:00' }],
sat: [{ open: '10:00', close: '14:00' }],
sun: 'closed'
},
holidays: [
{ date: '2025-12-24', closed: true, note: 'Christmas Eve' },
{ date: '2025-12-31', slots: [{ open: '09:00', close: '12:00' }] }
],
exceptions: [
{ date: '2025-08-20', closed: true, note: 'Inventory' },
{ date: '2025-08-22', slots: [{ open: '12:00', close: '20:00' }] }
],
locale: 'en-US'
})
bh.isOpenNow()
bh.isOpenAt('2025-08-22T18:30:00Z')
bh.nextOpen()
bh.nextClose()
bh.timeUntilClose()
bh.timeUntilOpen()
bh.todaysSlots()
bh.weeklySummary()Configuration
type WeekdayKey = 'mon'|'tue'|'wed'|'thu'|'fri'|'sat'|'sun'
type HHMM = `${number}${number}:${number}${number}`
type SlotInput = { open: HHMM, close: HHMM }
type DaySpec = 'closed' | SlotInput[]
type Holiday = { date: string, closed?: boolean, slots?: SlotInput[], note?: string }
type Exception = { date: string, closed?: boolean, slots?: SlotInput[], note?: string }
type Config = {
timezone: string
week: Record<WeekdayKey, DaySpec>
holidays?: Holiday[]
exceptions?: Exception[]
locale?: string
firstDayOfWeek?: WeekdayKey
strictValidation?: boolean
}Validation rules:
- Check HH:MM format for open/close times
- Allow overnight slots (open > close)
- No overlapping slots in the same day (after overnight normalization)
- Exceptions override holidays
strictValidation: truethrows errors for invalid configs,falseauto-corrects deterministically
Overnight & DST handling
- Overnight slots are split internally into day-bound ranges
- All calculations are timezone-aware using Luxon
- DST changes are handled via Luxon's
setZone
API reference
createBusinessHours(config: Config): BusinessHoursisOpenNow(): booleanisOpenAt(date: Date | string): booleannextOpen(from?: Date | string): { start: Date, end: Date } | nullnextClose(from?: Date | string): { at: Date } | nullcurrentSlot(at?: Date | string): { open: Date, close: Date } | nulltimeUntilClose(at?: Date | string): { ms: number, minutes: number } | nulltimeUntilOpen(at?: Date | string): { ms: number, minutes: number } | nulltodaysSlots(at?: Date | string): Array<{ open: Date, close: Date }>slotsOn(date: Date | string): Array<{ open: Date, close: Date }>weeklySummary(options?): string[] | stringlistUpcomingSlots(daysAhead?: number): Array<{ date: string, slots: Array<{ open: Date, close: Date }> }>withOverrides(overrides: Partial<Config>): BusinessHours
Examples
Time until close
const res = bh.timeUntilClose()
// { ms: number, minutes: number } | nullNext open slot
const res = bh.nextOpen()
// { start: Date, end: Date } | nullWeekly summary
bh.weeklySummary()
// ["Mon 09:00–12:00, 13:00–17:00", ...]Performance tips
- The library precompiles weekly slots and caches recent days (LRU up to 14 days)
- Prefer reusing a single instance per config
Changelog
- 0.1.0: Initial release
