Skip to content

API ​

T is the Temporal type you pass in. Functions that return a date return that same type.

Workday functions ​

These accept a PlainDate, PlainDateTime or ZonedDateTime.

FunctionReturns
isWorkday(date), isWeekend(date), isHoliday(date)boolean. Dates in extraWorkdays are always workdays.
addWorkdays(date, n), subtractWorkdays(date, n)T, n workdays away. With n = 0 it returns date. From a non-workday, +1 is the next workday.
nextWorkday(date), previousWorkday(date)T, the nearest workday after or before date.
rollForward(date), rollBackward(date)T, date itself if it is a workday, otherwise the next or previous one.
workdaysBetween(start, end)The number of workdays after start up to and including end, negative if end is earlier. workdaysBetween(d, addWorkdays(d, n)) is always n.
eachWorkday(start, end)A generator of the workdays from start to end, both included.
workdaysInMonth(date)T[], the workdays of the month of date, in its own calendar.
workdayOfMonth(date)The number of workdays in the month up to and including date. It is 1 on the first workday.
workdaysByWeek(start, end)T[][], the workdays from start to end grouped by week. Weeks start after the weekend.

Working time functions ​

These accept a PlainDateTime or ZonedDateTime and need the hours option.

FunctionReturns
isWorkingTime(dateTime)boolean
addWorkingTime(dateTime, duration), subtractWorkingTime(dateTime, duration)T. The duration is a Temporal.Duration or an object like { hours: 4 }, in hours or smaller units.
workingTimeBetween(start, end)A Temporal.Duration in hours and smaller units (PT27H30M), negative if end is earlier. To leave pauses out, pass { pauses } after the options, or as the third argument of a calendar's method.
rollForwardToWorkingTime(dateTime), rollBackwardToWorkingTime(dateTime)T, dateTime itself if it is working time, otherwise the next period start or previous period end.
getWorkingHours(date)The working periods of the date, like [['09:00', '17:00']].

Calendars and adapters ​

FunctionReturns
createWorkCalendar(options)All of the functions above with options built in. The working time functions are included when hours is set.
fromDateHolidays(holidays, { types }){ holidays, specialHours }, to spread into the options.

Options ​

OptionValueDefault
weekendDays of the week, numbered from 1 (Monday) to 7 (Sunday)[6, 7]
holidays'YYYY-MM-DD', 'MM-DD' (every year), Temporal.PlainDate, Temporal.PlainMonthDay, rules, or a function (date) => booleannone
observed'nearest', 'next', 'previous' or 'none', where holidays on a weekend are observed'none'
extraWorkdays'YYYY-MM-DD' or Temporal.PlainDate, days that are workdays even on a weekend or holidaynone
hours[[start, end], …] for every workday, or { 1: […], …, 7: […], default: […] }. Times are 'HH:MM', 'HH:MM:SS' or Temporal.PlainTime. '24:00' can end a period, and an end before the start is an overnight range.needed for working time
specialHours{ 'YYYY-MM-DD': [[start, end], …] } ([] means closed), or a function (date, regularHours) => hours | undefinednone

Invalid input throws a RangeError or TypeError that names the problem, including misspelled option names. If the options leave no workday or working time at all, the functions throw instead of searching forever.

Requirements ​

You need a Temporal implementation. Firefox 139+, Chrome 144+ and Node.js 26+ have one built in. Elsewhere, such as Safari on iOS or older Node versions, use a polyfill:

js
import 'temporal-polyfill/global'; // installs a global Temporal
// or, without touching globals:
import { Temporal } from 'temporal-polyfill';

temporal-polyfill is published as an ES module only, and Node 18 and Node 20 before 20.19 can't load ES modules with require(). In CommonJS code on those versions, use @js-temporal/polyfill, or load temporal-polyfill with await import('temporal-polyfill'):

js
const { Temporal } = require('@js-temporal/polyfill');
const { addWorkdays } = require('temporal-workdays');

Dates in other calendars (hebrew, japanese and so on) work. Weekends and holidays are matched on the ISO date, and results stay in the calendar of the input. Node.js 18 or later is required.

CI tests the package on Node 18 to 26, Deno, Bun, Chromium, Firefox, WebKit and Cloudflare Workers, with temporal-polyfill, with @js-temporal/polyfill and with native Temporal where the runtime has it.

Released under the MIT License.