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.
| Function | Returns |
|---|---|
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.
| Function | Returns |
|---|---|
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
| Function | Returns |
|---|---|
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
| Option | Value | Default |
|---|---|---|
weekend | Days 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) => boolean | none |
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 holiday | none |
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 | undefined | none |
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:
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'):
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.