@wizyter/time-slots-finder

A module to extract available time slots from a calendar.

Usage no npm install needed!

<script type="module">
  import wizyterTimeSlotsFinder from 'https://cdn.skypack.dev/@wizyter/time-slots-finder';
</script>

README

Time Slots Finder

Module Version License Bundle Size Maintainability Test Coverage

An API to get available time slots. It's possible to provide a calendar containing existing events.

Disclaimer

This module is currently still in pre-version. BREAKING CHANGES may occurs in MINOR versions. Use it with care.

Features

  • Define slots duration
  • Require free time before and/or after slots
  • Define bookable shifts for day of the week
  • Work with or without calendar data
  • Handle iCal format for calendar data
  • Take time zones in account when parsing calendar and for the configuration
  • Includes TypeScript definitions
  • High test coverage

Install

npm install --save time-slots-finder
yarn add time-slots-finder

Documentation

Usage

import * as TimeSlotsFinder from "time-slots-finder"

const slots = TimeSlotsFinder.getAvailableTimeSlotsInCalendar({
    calendarData: "SOME ICAL DATA",
    calendarFormat: TimeSlotsFinder.TimeSlotsFinderCalendarFormat.iCal,
    configuration: {
        timeSlotDuration: 15,
        minAvailableTimeBeforeSlot: 5,
        minTimeBeforeFirstSlot: 48 * 60, // 48 hours in minutes
        availablePeriods: [{
            isoWeekDay: 5,
            shifts: [{ startTime: "10:00", endTime: "20:00" }] 
        }, {
            isoWeekDay: 6,
            shifts: [
                { startTime: "10:00", endTime: "20:00" },
                { startTime: "10:00", endTime: "13:00" },
            ]
        }],
        timeZone: "Europe/Paris",   
    },
    from: new Date("2020-09-21T00:00:00.000+02:00"),
    to: new Date("2020-11-12T23:59:59.999+02:00"),
})

/**
 * This will returns all free time slots between September's 21th and
 * November's 12th, only for all Friday from 10 AM to 8 PM (Paris time) and
 * Satursday from 10 AM to 1 PM. All slots will be 15 minutes long with 5
 * minutes free before each. If we were the 21th of September the first slot
 * would have been on the the 23th (since we require 48 hours before the first
 * availabilities.
 */

A TimeSlot is represented as follows:

{
    /* The start date of the period */
    startAt: Date
    /* The end date of the period */
    endAt: Date
    /* The duration of the slot in minutes */
    duration: number
}

Configuration options

/* Required. The length of the time slots in minutes. */
timeSlotDuration: number
/**
 * A number indicating the step for the start minute of a slot.
 * E.g. if the multiple is 15, slots can only begin at XX:00, XX:15, XX:30 or XX:45.
 * Default value is 5.
 */
slotStartMinuteStep: number
/* Required. Bookable periods for each day of the week. */
availablePeriods: [{
    isoWeekDay: number, // 1 (Monday) - 7 (Sunday)
    shifts: [{
        startTime: string, // Format "HH:mm"
        endTime: string, // Format "HH:mm"
    }]
}]
/**
 * Periods where no booking is allowed.
 * 
 * Objet containing at least month and day values.
 * If years are ommited, event repeat every years.
 * If hour are ommited, all day is included: hour 00:00 is used for startAt and 23:59 is used for
 * endAt.
 * Month are 0 indexed, i.e. January is 0 and December is 11. 
 * An unavailable period MUST have year defined for BOTH OR NONE of startAt and endAt.
 */
unavailablePeriods: [{
    startAt: { year?: number, month: number, day: number, hour?: number, minute?: number },
    endAt: { year?: number, month: number, day: number, hour?: number, minute?: number },
}]
/* The minimum number of free minutes required before a slot. */
minAvailableTimeBeforeSlot: number
/* The minimum number of free minutes required after a slot. */
minAvailableTimeAfterSlot: number
/**
 * The minimum number of minutes between the time of the search and the first slot
 * returned.
 */
minTimeBeforeFirstSlot: number
/* The maximum days from now before slots cannot be returned anymore. */
maxDaysBeforeLastSlot: number
/* Required. The time zone used through all the configuration. */
timeZone: string

See the time zones list here.

Advanced usage

If you want to check that a configuration is valid without running a search, you can use the isConfigurationValid function as follows:

import * as TimeSlotsFinder from "time-slots-finder"

const config = {
    timeSlotDuration: 15,
    availablePeriods: [{
        isoWeekDay: 5,
        shifts: [{ startTime: "20:00", endTime: "10:00" }] 
    }, {
        isoWeekDay: 6,
        shifts: [
            { startTime: "10:00", endTime: "20:00" },
            { startTime: "10:00", endTime: "13:00" },
        ]
    }],
    timeZone: "Europe/Paris",   
}

try {
    TimeSlotsFinder.isConfigurationValid(config) // returns true is valid
} catch (error) {
    /**
     * Throws error if configuration is invalid.
     * The error indicate why and where the configuration is invalid.
     *
     * Here the error is:
     * "TimeSlotsFinderError: Daily shift 20:00 - 10:00 for work period nÂș1 is invalid"
     */
}

What's next?

  • We consider handling more calendar formats in the future.
  • The API may change until the first version (v1.0.0) is released