Count approval periods in business days and hours using work calendars
Description
Problem
Every period counts calendar time, including weekends, nights and holidays: a 3-day "Approval decision deadline" started on Friday expires on Monday, leaving one working day. Admins cannot define working days, hours or holidays.
Change
Work calendars
-
New page Settings > Work calendars, in Jira and Confluence, for global admins. Up to 50 calendars per site.
-
A calendar has:
-
Name: required, up to 80 characters, unique on the site.
-
Time zone: a region zone (e.g. Europe/Warsaw) or UTC, the admin's zone by default; hours and holidays use it.
-
Working days: at least one, Monday to Friday by default.
-
Working hours: "All day", or one range for all working days, 09:00-17:00 by default. A range that does not start before it ends shows "Working hours must start before they end."
-
Public holidays: a country (Jollyday data, 226 countries) and a first-level region where regions have holidays of their own (16 in Germany, none in Poland), counted live for every year, observed days included (US 4 July 2026 on Friday 3 July; New Year 2028 on Friday 31 December 2027), and only the observed day counts (a calendar working Saturdays works on Saturday 25 December 2027 in the UK; add it as a custom holiday). Only public holidays, no bank holidays or observances; English names. A table per year (arrows, last year to 10 years ahead) lists the holidays with a "Working day" box; a holiday marked as a working day is one every year with its substitute days, same-named holidays together (Irish bank holidays), up to 50. A new calendar takes the global default country; without one it takes the country of its time zone and follows time zone changes (none for a zone without data) until a country or region is picked or a holiday is marked. Another or no country clears the region and the marks; another region clears the marks.
-
Custom holidays: date, name and "Every year" (same day and month every year, 29 February only in leap years). Up to 200, years 2000 to 2099. Edit loads a holiday into the add row; Add, or Save with the row filled, puts it back. Edit is disabled while the add row holds a draft: "Add or clear the holiday below first."
-
-
The list shows name, time zone, working days and hours, public holiday country and region, custom holidays, definitions using it and a "Default" label. Row actions: Edit, Set as default, Delete. A failed load shows "Failed to load work calendars" with Retry.
-
Default calendar and deleting:
-
The first calendar becomes the default. Definitions that do not pick a calendar use the default.
-
Delete is disabled on the default while other calendars exist, tooltip "Set another calendar as default first."
-
The last calendar cannot be deleted while a definition counts in business time, the global default is on, or approvals in progress count periods in business time; the dialog and server say which (up to 5 definitions).
-
The confirmation names the definitions using it; they use the default calendar afterwards. Approvals in progress using it switch to the default calendar for periods counted after the deletion; the dialog says so.
-
-
Global settings on the same page: "Preselect business time in new definitions", description "Also preselected in definitions saved before work calendars existed. Admins can uncheck it in each definition." Disabled until a calendar exists; the server refuses turning it on without one. "Default holiday country" (none by default) for new calendars; an unknown country is refused.
Business time on definitions
-
New definition section "Business time":
-
Checkbox "Count periods in business time" with a visible description: "Hours and days count only the working time of the work calendar: decision deadline, validity expiration, automatic reminders, voting deadlines and periods entered when parametrizing an approval. Weeks, months and years count as calendar time."
-
Select "Work calendar": "Default calendar ()" and every calendar.
-
With no calendar the checkbox is disabled: "Create a work calendar in Settings > Work calendars first." for global admins, "Ask an admin to create a work calendar." for others.
-
-
While it is on, the unit selects read "Business hour", "Business day", "Week", "Month", "Year".
-
Definitions saved before this change have no choice stored (calendar time). With the global setting on, creating, editing or duplicating such a definition preselects business time and opens the section; viewing never does. A saved choice is kept.
-
Periods that exceed their maximum in business time (e.g. max 2 days, default 24 hours, 09:00-17:00: 2 business days = 16 business hours):
-
Turning business time on or changing the calendar reduces them to fit; turning it off restores the entered values.
-
Create and Duplicate, and Edit of a definition that counts in business time, reduce them when the editor opens.
-
Edit with business time only preselected keeps the stored values and shows an inline error, e.g. "Default deadline can't exceed the maximum of 2 business days (16 business hours)."; Save is blocked with the same message, never by the browser's validation bubble.
-
Values that fit are never changed; business days are not converted to hours.
-
-
"Duplicate" copies the choice and the calendar.
-
An approval keeps the counting and the calendar resolved at start (the default calendar of that moment when the definition uses the default). Later calendar edits apply to periods counted after them (reminders, validity on approval, voting deadlines); dates already set do not move.
How business time is counted
-
Working time: the working hours of working days that are not holidays, in the calendar's time zone; the whole day without working hours.
-
Starts are taken to the minute; the end is the first moment the working time has passed, so a period that fits a working day exactly ends at the end of that day.
-
Business hours count working time; a start outside it counts from the next working time. 09:00-17:00: Monday 16:00 + 2 business hours = Tuesday 10:00.
-
One business day is the working time of one working day (the working hours, or 24 hours). Started during working hours it ends at the same time of day; started at the start of working hours or outside them, at the end of a working day: Saturday 12:00 + 1 business day = Monday 17:00.
-
Working hours follow the calendar's local clock (daylight saving does not shift them; an "All day" working day is 24 hours; in the repeated hour the first occurrence is used). Weeks, months and years count as calendar time in the starter's time zone, as today. Minute reminder intervals (test environments only) count working minutes.
-
A period ending more than about 10 years of calendar dates after its start (e.g. 100 business hours with one working minute a day) cannot be dated. A shorter maximum caps it at the maximum date; only without one is the start refused: " () is too long.". Such a validity period without a maximum sets no date on approval, such a voting period no deadline. Lists and comparisons treat it as longer than any other period.
Where business time applies
For approvals of a definition that counts in business time, with the definition's calendar:
-
Decision deadline and validity: the definition's and global defaults and maxima (the stricter maximum is the earlier date), "Valid for" counted from the start or from the approval, and the "Valid until" dialog maximum.
-
Automatic reminders: exactly 3 per step after the last decision; reminder k is due k x the interval of working time after it, and is sent only in working time: one due outside it, or missed (e.g. an outage), goes at the next sweep in working time; the next is due at the next interval mark. The stored count keeps it at 3 when the calendar is edited mid-step. Weekly intervals count calendar weeks, sent in working time. Calendar-time reminders unchanged.
-
Parametrize: "Deadline in", "Valid for" and "Reminder interval" show business units, default and latest dates use the calendar, and the page says "Hours and days count only the working time of the '' work calendar." When the calendar can't be used (not loaded, or a zone the browser doesn't support), it shows "Work calendar unavailable" instead of the form.
-
Every start: Start, Parametrize, workflow post-function, Automation, Web API, Rovo, JSM portal, rerun and relaunch. A restart that keeps a "Deadline in" period counts it again from the restart.
-
Texts show the counting, e.g. "3 business days": summaries, the "reduced to the maximum" warning, server errors.
Save checks compare same-kind periods only (business hours with business days via the working-day length); mixed kinds are not compared when saving, but are capped at the earlier maximum at start. Global settings (Approval expiration, Notifications) show under their period rows "In definitions that count in business time, hours and days of this period count only the working time of the definition's work calendar." and are validated in calendar time as today.
Voting deadline period
-
Vote step "Voting deadline": "No deadline", "Date and time" (as today) or "Period after the step starts", 1 to 100 hours, days or weeks, in business units when the definition counts in business time.
-
The deadline is computed and stored when the vote step starts, with the approval's counting, also for a step started by a work item field change. Votes, the "voting expired" message and every channel use it like a date today.
-
While the step waits to start in an approval in progress, the approval panel and the approval page opened from emails show "Voting deadline: 3 business days after the step starts"; steps that will not start show nothing.
-
The server checks the period (a number and a unit, 1 to 100, hours, days or weeks, not with a date), from the editor and the Web API, naming the step.
-
Stored dates are not migrated.
Web API v2
-
Definitions:
businessTimeandworkCalendarId(null = default calendar). Vote steps:votingPeriodValue,votingPeriodUnit. -
An unknown calendar or one of another site is refused (400), and so is
businessTime: truewithout calendars. -
Absent
businessTimeon create:truewhen the global setting is on, otherwise nothing is stored (calendar time). Absent on update: the stored value is kept, andworkCalendarIdnull or absent keeps the stored calendar; to switch to the default calendar, sendbusinessTimetoo. Deadline and validity settings are merged with global settings using the resulting counting and the same-kind rule, never depending on the weekday.
Related fixes included (Web API v2)
-
PUT /definitions/{id}andPUT /conditions/{id}check access to the stored project (global access for a global one) as well as to the body's project, as GET and DELETE do. A missing definition or condition is 404 first. -
A project key in
collectionIdis stored as the project id, for definitions and conditions. An unknown project is 404 "Project[id or key: X] not found" (was 400). -
One Atlassian lookup less per create and update: the separate project check is gone, the access check resolves the project. Create checks access before validating the body.
Decisions
-
One switch per definition; one working-hours range per calendar; public holidays from Jollyday counted live, not copied into the calendar; custom holidays entered by hand, with "Every year".
-
Global periods count in business time for business-time definitions. A deleted calendar falls back to the default, for definitions and running approvals, as Slack connections do.
Out of scope
-
Charts, reports, the home feed "Due in" and approval ages stay calendar time. Requested periods on Web API and Rovo starts: AP-2488. Voting deadline on Parametrize, the voting timer, passed fixed vote dates: AP-2495.
-
Per-weekday hours, JSM SLA calendar import, calendar history, changing a running deadline. A public holiday as a working day on one date only. Countries Jollyday lacks (e.g. CN, TH, MY) use custom holidays.
-
Keyboard access to hover-only row actions: separate ticket.
Acceptance criteria
-
Monday to Friday: Friday 10:00 + 3 business days = Wednesday 10:00; with 09:00-17:00, Friday 18:00 + 8 business hours = Monday 17:00. Holidays, also "Every year" ones in later years, do not count.
-
Poland: Tuesday 10 November 2026 10:00 + 1 business day = Thursday 12 November 10:00; with Independence Day marked as a working day, Wednesday 11 November 10:00. Germany does not count 6 January nationally, Bavaria does. Christmas marked in Australia also makes its substitute Monday 27 December 2027 a working day.
-
Two definitions with different calendars count the same period by their own calendar. Validity, reminders, voting deadline and Parametrize periods follow the calendar; definitions without business time count as today.
-
At most 3 automatic reminders per step after the last decision, none outside working time, also after a calendar edit mid-step; a missed reminder is sent at the next check in working time.
-
The global default preselects business time in new and edited definitions; the admin can switch it off. Edit never changes stored periods; one over its business-time maximum shows the inline error and blocks Save.
-
A user who may not parametrize, or a JSM customer, cannot set a period with a crafted request.
-
A restart keeping "Deadline in 3 business days" gets 3 business days from the restart.
-
A vote step period gives a deadline when the step starts, also for a later step or a field-change start. Only a waiting step that can still start shows the period text.
-
Delete is disabled on the default calendar while others exist; the last calendar cannot be deleted while definitions, the global default or approvals in progress count in business time; definitions and approvals in progress of a deleted calendar use the default one. A calendar of another site cannot be used (editor, Web API).
-
A period beyond the 10-year horizon is capped by a maximum, refused only without one; the definitions list loads.
-
Parametrize with an unusable calendar shows "Work calendar unavailable" and cannot start.
-
A Web API v2 update cannot change a definition or condition whose stored project the key's owner cannot access.
Manual tester notes
-
America/New_York calendar, tester in Europe/Warsaw: hours apply in New York time, dates in the tester's zone. A business-day period across 25 October 2026 keeps the time of day.
-
Reminders on qa: working hours ending in a few minutes, a 5-minute business interval. Reminders stop at the end of working hours, resume at the next start, exactly 3 per step; changing the hours after the first one keeps 3.
-
Starts from the workflow post-function, Automation, Web API v2, Rovo and the JSM portal count in business time.
-
Confluence rerun after a page change with "Deadline in 3 business days" and a Required deadline.
-
"Valid for" from the approval date and the "Valid until" dialog maximum, in business time.
-
Vote step period as the second step and started by a field change: the deadline appears when it starts, in the panel, the Jira notification, Slack and Rovo; before that the panel and the email dashboard show the period, after the approval ends they don't.
-
Public holidays: Europe/Warsaw admin creates a calendar (Poland preselected), switches the time zone to New York (United States), Shanghai (no country) and back; with a global default country the country stays when the time zone changes; a picked country stops following the time zone. Germany with and without Bavaria, a working day kept in the next year, a deadline across 11 November in Poland.
-
Calendars: delete one in use; Delete on the default with others (disabled); the last calendar with an approval in progress (blocked); change the default; add and edit a holiday on a calendar with running approvals.
-
Editor: preselect on, global Custom max 2 days, default 24 hours, 09:00-17:00. Create shows 16 business hours; Edit of an old definition keeps 24 with the inline error and blocked Save; unchecking business time clears it.
-
Parametrize with the calendars request blocked in the browser: "Work calendar unavailable".
-
A JSM customer viewing a business-time definition in the portal sees no error. Repeat the cases in Confluence.
-
Related fixes: POST a definition and a condition with a project key; GET returns the project id. PUT moving one to another project works for an admin key owner, is refused for a non-admin. Unknown project on POST or PUT: 404.