Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Automation concepts – Increment a Date While Skipping Holidays

Estimated time to read: 12 minutes
 
TL; DR: When incrementing a date by business days, we may want to skip any holidays / non-working days. Let's build a rule help do that!
 
 

What problem are we solving?

 

When a team uses date fields such as Due Date, they may want to increment them by a specific amount. Automation rules support various increment units, including the function plusBusinessDays(). And, Jira board settings have a configuration to define the Standard Working Days and a list of Non-working Dates. But, neither of those values are used with automation functions. Instead, automation uses a fixed definition of business days: Monday to Friday, 9am to 6pm.
 
Observation: This design choice has bothered me for years. One can understand a need for different spaces (formerly called projects) and boards supporting a different list of working / non-working days. Teams could be in different geographic locations, have different employment relationships, etc. However, why not have a Jira site definition of working day / non-working date lists and add association tables for which space / board uses which values? Certainly, the current design seems to sprawl the data unnecessarily.
  
There is are suggestions to add handling of non-working days to rule functions and which would likely need a change to the REST API. You may watch / vote for those suggestions to see progress. Until those features are added, how might we solve this with existing automation features?
 

Ways to solve it…and some limitations

 

Many may consider holidays to also be called "non-working days"; let's use the term "holidays" for the remainder of this article for consistency.
 
I can think of at least two ways to solve this: math and lists. I have implemented both of these techniques with rules, and found both have limitations.
 
  1. Math – For a starting date, increment it using the built-in business days functions. Then count any holidays within that date range (i.e., starting date -> ending date), and use that count to increment again. Repeat these steps until no further increments are found.
  2. Lists – For a starting date, generate an ordered list of possible business dates into the future (e.g. out to a few hundred days). Remove any known holidays from the list to shorten it. The last step is now easy: we index into the remaining date list with the desired increment to find the date.
 
The first method is difficult as automation rules do not have sequential branching or recursion within a single rule's scope. There are workarounds for these difficulties, yet the resulting rule is quite complicated. (As an aside, the newer branching features for Premium / Enterprise license levels may help, although I have not tried those.) The second approach with lists is simpler, and it relies upon some assumptions about list behavior and how large the increment may be.
 
Let's build the second approach using lists as it is simpler to try.
 

Approach walkthrough

 

We briefly described the list approach, and let's add a visual to help describe it further:
 
list solution approach - Copy - Copy.png
 
In this example, we have a Start Date of 5 January 2026, or 2026-01-05 in jiraDate format. We want to increment that by 35 business days, skipping over the holidays in our list. For this example, and rule, I am using some common federal holidays in the United States during 2026.
 
  1. We count out a bunch of business days. Let's go out a few hundred to make a list. Note this list still contains the holiday dates.
  2. We use the values in the holidays list to strip out any matching dates, compressing the resulting list to update the indices, from 0 to N. That "strip out" will happen later using a regular expression.
  3. The last step is now easy as we just find the 35-th entry in the list, and that is the answer date: 2026-02-25.
 

How to build the rule

 

As with many of my sample rules, we will use a Scheduled Trigger and write results using the Log action. This is a helpful tip to build many rules, experiment a lot, and not consume your valuable monthly usage counts / limits. You may adjust later for your specific rule needs: trigger, actions, etc.
 
Here is a picture of the complete rule, with the audit log showing a sample execution. This rule uses techniques from a couple of earlier articles, and I will add links to those where they apply.
rule and audit log - Copy - Copy.png
 
And for the specifics of the rule components...
  • trigger: Scheduled 
  • action: Log, to add a reminder for the holidays table content
  • action: Create Lookup Table 
    • Lookup table variable name: varHolidays
    • Table entries
      • Row
        • Key: some holiday name
        • Value: holiday date, formatted as yyyy-MM-dd; e.g. 2026-01-01
      • ...
increment date with skipping holidays, rule, lookup table - Copy - Copy.png
  
The order of holidays in the table does not matter, and new ones may be added later. And while there is a reminder to only include weekdays in the table, values for weekend holidays will not break the rule. The log reminder helps consider observed versus actual holiday dates, such as for Independence Day 2026 in the US on 2026-07-03.
 
  • action: Create Variable 
    • Variable name: varNull
    • Smart value: {{null}}
  • action: Create Variable
    • Variable name: varStartDate
    • Smart value: {{#debug}}2026-01-05{{/}}
  • action: Create Variable
    • Variable name: varIncrement
    • Smart value: {{#debug}}35{{/}}
  • action: Create Variable
    • Variable name: varBusinessDaysList
    • Smart value:
{{#debug}}{{#varNull.rightPad(1000, "~,").substringBeforeLast(",").replace("~", varStartDate).split(",")}}{{#toDate("yyyy-MM-dd")}}func=plusBusinessDays({{index}}),format="jiraDate"{{/}}{{^last}},{{/}}{{/}}{{/}}

How that works is:

  • Using our varNull technique to start with an empty string
  • We create a boilerplate string using rightPad(). Note the count is 1000, which helps us add 500 days (where there are 2 characters of tilde and comma for each item)
  • Dropping off the last comma with the substringBeforeLast() function 
  • We replace() the tildes with the varStartDate value
  • Split() into a list of unnamed attributes, where each is the starting date
  • Now comes the tricky part: we switch syntaxes to the long format of date incrementing by converting the string with toDate, add business days using its index position in the list, and format the result as a jirDate
  • We add comma delimiters between the items
  • And finally wrap that in a {{#debug}} … {{/}} expression so it writes to the audit log

 

  • action: Create Variable
    • Variable name: varRegEx
    • Smart value:
{{#debug}}^((?!({{varHolidays.entries.value.trim.replace("-","\-").join("|")}})).*){{/}} 

 How that works is:

  • We want a regular expression which excludes values, and regex can do that with a negative lookahead
  • Using the varHolidays table, we get all the entries
  • Pulling out only the value with the dates; the key value (holiday name) is not needed
  • To reduce errors, we trim any spacing, and add escapes for the dash characters with replace() 
  • We join() the list items with pipe characters to create a string
  • And finish the syntax to complete the regular expression

 

  •  action: Create Variable
    • Variable name: varFinalDate
    • Smart value:
{{#debug}}{{varBusinessDaysList.split(",").match(varRegEx).get(varNull.length().plus(varIncrement.asNumber))}}{{/}}

 How that works to get the final date is:

  • Using our full list of business days, we split() that back into a list
  • With the match() function and our regular expression, we remove the holidays
  • And now we can get() the correct date…
  • Our varIncrement is stored in a variable, and thus we once again use our varNull technique to use that as a number; if instead, you have the increment stored in a number field, it may be used directly

 

  • action: Log, to display the results in the audit log
start on {{varStartDate}} incremented by {{varIncrement}} business day(s) to {{varFinalDate}}
 

Testing the rule

 

To test this rule, I used a modified version with a list of starting dates, increments, and expected results stored in a created variable. Then with an Advanced Branch, I iterated the tests and to process each one. You may test it in the same manner or with single date values and repeated rule executions. Please remember to first update to your holiday list and watch the audit log for problems!
 

Other options, additional exercises, etc.

 

Remember my observation about the "sprawl" of having the holidays in different spaces / boards? This rule approach makes the situation worse as we have added the dates in a lookup table…in as many rules as we use it! What can we do instead?
 
Well…there is an old, unsupported, no longer documented, GreenHopper REST API endpoint to get a board configuration, and that does contain the non-working dates. Thus, one could use that as the holiday source with a Create Dynamic Lookup Table, or Create Variable as a list. Given all the caveats at the start of this paragraph, I suggest "buyer beware" when using old, undocumented stuff. If you still want to try it, please see this Atlassian Developer Community post to find the endpoint information.
 
A few other options to reduce replication of the holiday list and store it in one place are:
  • Store the holidays in an entity property as JSON for one space (i.e., project). Then read the property with the Send Web Request action and the REST API from any project. Parse the JSON from the web response to use the holidays in the rule.
  • Use an Incoming Webhook Trigger rule for all date increments, and "call" that rule from your own rules with the Send Web Request action
  • Create a specific space to hold holidays, with a work item (e.g., Story) to represent each holiday date. Limit access to the space, as needed. Now use either the Lookup Work Items action or the REST API work item search endpoints to get the data, parsing it for use as the holidays.
 
 
One more thing: what if instead one wants business date difference counts, excluding holidays, rather than incrementing a date? Please consider you would know the holidays, the start date, and the final date. With those, and the techniques described in this article, one could build a list from the start to end date, remove the holidays, and get the diff count from the size of the resulting list.
 
 

Wrapping it up...

 

So, would anyone ever use this rule? Maybe…
 
I hypothesize no changes to the storage of non-working dates in a single location from Atlassian any time soon. Or, the creation of new endpoints to access them. When your team wants this type of date increment, maybe try this rule approach to observe what happens and how it helps.
 
Even if you do not use the described rule, I hope you learned something from the techniques shown. Please let me know your feedback, and your interest in the messy "math" version of the solution too. And as always…
 
Happy rule writing!
 

1 comment

Rudy Holtkamp
Community Champion
November 18, 2025

Hi @Bill Sheboy


@Bill Sheboy ,

Did you ever considered using something like Working days API  https://share.google/eSVsW9C8VW8V3zGnu

As a solution for this problem?

Comment

Log in or Sign up to comment
TAGS
AUG Leaders

Atlassian Community Events