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. You could use an external service endpoint to do so. Or...let's build a rule help solve it!
 
 

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 days / non-working dates. 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.

When community questions ask how to solve this, I have sometimes suggested using an external service endpoint, purpose-built for it, such as described in this comment to the article. The focus of this article is how to solve this with a rule using built-in automation features, such as dynamic list creation and filtering.

 
I can think of at least two ways to solve this with rules: 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, revised - Copy.png
 
In this example, we have a Start Date of 5 February 2026, or 2026-02-05 in jiraDate format. We want to increment that by 10 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 10-th entry in the list, and that is the answer date: 2026-02-20.
 

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 another sample execution, with a different Start Date and Increment than our earlier one. 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). We actually only need the Increment plus the number of holiday table rows plus a couple more for safety, but using 500 is simpler for the example.
  • 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 jiraDate
  • 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...or maybe not. When your team wants this type of date increment, maybe try this rule approach to observe what happens and how it helps. Or if you want a faster, pre-built solution, please try one of the external service endpoints to do this.
 
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!
 

4 comments

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?

Like # people like this
Bill Sheboy
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
November 19, 2025

Hi @Rudy Holtkamp 

Thanks for the feedback!

When community questions ask how to solve this need, I have sometimes suggested using an external service endpoint, purpose-built for it. My intent for the article was the methods to solve it with the built-in features...such as dynamic list creation and filtering. I updated the article to note this distinction and to link to your comment with the external reference.  Thanks, again!

Kind regards,
Bill

Like # people like this
Susan Waldrip
Community Champion
November 19, 2025

@Bill Sheboy , this is a GREAT article with really helpful detail and visuals. I hope to try this very soon, thank you!

Like # people like this
jerlyn.brital
Contributor
November 23, 2025

I find it really helpful for future tasks/projects. Thank you so much! 

Like # people like this

Comment

Log in or Sign up to comment
TAGS
AUG Leaders

Atlassian Community Events