Skip to content

Calendars

This page is for a PM or scheduler who wants finish dates that reflect real availability, not just a raw day count. A calendar defines which days are working days and how many hours a working day holds. The scheduling engine uses its working days and exceptions to convert a task’s duration (expressed in working days) into real calendar dates — skipping weekends and holidays so your finish dates reflect actual availability.

SettingMeaning
Working daysWhich days of the week count as working (default Monday–Friday).
Hours per dayLength of a working day. Accepts fractions — set 6.0 for a six-hour day.
Time zoneAn IANA zone name such as Europe/Berlin (default UTC); a non-IANA value like Pacific Time is rejected on save, and the field cannot be blank.
ExceptionsDate ranges that override the weekly pattern — public holidays, company shutdowns, or one-off non-working spans.

The time zone is recorded for API parity only — like hours per day, it round-trips on every read, but it is not consumed by CPM or Monte Carlo and never changes a computed date; see Calendar arithmetic.

Hours per day is a decimal, so part-time and custom-hour teams can record their real day length. It is used in three places:

  • Resource capacity. The resource heatmap and the project Overview’s Team utilization card compute a resource’s daily capacity as hours per day × units, and the sprint capacity preflight counts committed and available hours the same way.
  • Estimates entered in hours. An #4h-style estimate is divided by the project calendar’s hours per day and rounded up to whole days when you enter it, so 7h is two days on a 6-hour calendar and one day on an 8-hour one — see Schedule build mode. The task stores the whole-day count. Changing hours per day later keeps that day count. A task whose duration unit is set to hours then reads differently (two stored days show as 12h on a 6-hour calendar, 16h on an 8-hour one); a task shown in days is unaffected.
  • It does not change how the scheduler counts a duration that is already in days. The engine counts whole working days, so a 5-day task spans the same elapsed days on a 6-hour calendar as on an 8-hour one. Sub-day scheduling is planned for 0.6.

A calendar attaches to a project — every task in that project schedules against it by default. A resource can carry its own calendar to model an individual’s availability (for example, someone who doesn’t work Fridays); where a resource has no calendar, the project’s calendar applies.

A project’s effective non-working time will be the overlay (union) of every calendar applied to it, not just a single calendar. A project will apply:

  • a base project calendar — the org standard work week and hours;
  • a reusable holidays calendar — public holidays, created once and applied to many projects; and
  • an optional workspace / shutdown calendar — for an org-wide winter shutdown.

A day counts as non-working if any applied calendar marks it so: the weekly patterns compose by intersection (a weekday is working only when every applied calendar treats it as working) and the holiday/shutdown exceptions compose by union. Because the overlay is a union, the order calendars appear in is a display grouping only — it never changes the computed schedule.

A Working calendars panel in Project Settings will let anyone with the Resource Manager (Scheduler) role or above apply and reorder a project’s calendars and preview the effective working time day-by-day — each non-working day showing which applied calendar blocked it. Reading the applied set and its preview will be open to any project member; changing it will require the Resource Manager role, the same gate as editing the schedule.

Applying calendars to a project draws only on the shared calendar library — the same calendars managed below. Per-resource / PTO calendars that make a task’s duration depend on who is assigned, holiday-feed (iCal) import, and cross-program calendar governance are not part of this release.

Method & pathPurpose
GET /api/v1/projects/{id}/calendars/The calendars applied to a project (base + overlays)
PUT /api/v1/projects/{id}/calendars/Replace the applied set (base calendar + ordered overlays)
GET /api/v1/projects/{id}/calendars/preview/?start=&end=Per-day effective working time, with the source that blocked each non-working day

When the scheduling engine works out task dates, non-working days — weekends, plus any day inside a calendar exception — are skipped entirely. A task with a 5-day duration starting on a Thursday finishes the following Wednesday on a Monday–Friday calendar, not the following Monday. Add a holiday exception in that span and the finish slides another day.

Calendars are managed via the REST API (a visual settings editor is planned):

Method & pathPurpose
GET /api/v1/calendars/List calendars
POST /api/v1/calendars/Create a calendar
GET /api/v1/calendars/{id}/Retrieve (with exceptions)
PATCH /api/v1/calendars/{id}/Update
DELETE /api/v1/calendars/{id}/Delete

Any authenticated user can read calendars — a project member has to be able to see which calendar schedules their plan. Creating, editing, and deleting them requires the workspace Admin role (or Owner): a calendar is shared, so changing its working days or exceptions moves finish dates on every project bound to it, including projects the editor is not a member of. A project-level role — even Owner — is not enough, because anyone can create a project and become its Owner. This is the same role that sets the workspace default calendar, so editing a shared calendar’s contents is no easier than pointing a project at a different one.

A DELETE that would orphan a live schedule is refused with 409 and a body naming what still references the calendar, so you can detach those first. Projects and programs you are not a member of appear in that list by id only, without their name; the reference_count still counts them, so the refusal tells you how much is blocking even where it cannot tell you what.

Exceptions — the holiday and shutdown date ranges that override a calendar’s weekly pattern — are managed through a nested sub-resource on the calendar. The exceptions sub-resource landed in 0.4.

Method & pathPurpose
GET /api/v1/calendars/{id}/exceptions/List a calendar’s exceptions
POST /api/v1/calendars/{id}/exceptions/Add an exception
GET /api/v1/calendars/{id}/exceptions/{exc_id}/Retrieve one exception
PATCH /api/v1/calendars/{id}/exceptions/{exc_id}/Edit an exception
DELETE /api/v1/calendars/{id}/exceptions/{exc_id}/Remove an exception

An exception carries a start date (exc_start), an end date (exc_end), and an optional description. Set exc_start equal to exc_end for a single non-working day; exc_end must fall on or after exc_start. Overlapping ranges are allowed — the scheduler treats their union as non-working.

The parent calendar is taken from the URL, never the request body: an exception always belongs to the calendar it was created under and cannot be reassigned. Any authenticated user can read exceptions; creating, editing, and deleting them requires the workspace Admin role — the same gate as editing the calendar itself, and for the same reason: one holiday added here moves finish dates on every project bound to the calendar.

Adding, editing, or removing an exception recomputes every project scheduled against the calendar — whether the calendar is that project’s base or one of its overlays — so dependent task dates stay true to the new working time. The change also syncs down automatically to anyone working offline, so critical-path calculations made without a connection still account for holidays. (Offline recompute currently only accounts for a project’s base calendar, not any additional calendars layered on top — a tracked follow-up; the server always computes against the full combined set.)