Forums

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

Jira Server Scriptrunner: Set Due Date based on Custom Field Selection, Excluding Weekends

Megan D August 6, 2024

What I need:

A due date to be auto-filled based on what custom dropdown field already says, but to also account for our weekend.

Dropdown selection is:

Request Complexity: (custom field: 14220)

  • Simple (3 days)
  • Average (7 days)
  • Complex (14 days)

The days in italics (above) are how much time to add to the current date for the due date.

Due Date (custom field: 14233)

  • Needs to account for the weekend (ours is Friday-Sunday).
    • Example: if a user starts this process on a Thursday, and the request is a "Simple" complexity, it would actually be due on Tuesday since we "skip" Friday-Sunday.

What I have:

This is my current code, but it doesn't account for the weekend, but it also doesn't work as-is. I would greatly appreciate any help or code you can provide. Thank you!

import com.atlassian.jira.component.ComponentAccessor
import java.text.SimpleDateFormat

def customFieldManager = ComponentAccessor.customFieldManager
def duedate = customFieldManager.getCustomFieldObjects(14233)

def complexityField = customFieldManager.getCustomFieldObjects(14220)
def complexityFieldValue = issue.getCustomFieldValue(complexityField).value.toString()

def dateFormat = new SimpleDateFormat("d/MMM/yy")
def duedateValue = dateFormat.parse(issue.getCustomFieldValue(duedate).toString())

if(complexityFieldValue == "Simple"){
    duedateValue + 3} 
else if(complexityFieldValue == "Average"){
    duedateValue + 7} 
else if(complexityFieldValue == "Complex"){
    duedateValue + 14}

 

3 answers

2 votes
Tuncay Senturk
Community Champion
August 7, 2024

Hi @Megan D 

First of all, I must admit I'm a bit envious that you have 3-day weekends including Fridays :D

Below, I tried to write some code/functions that could provide some help, please be aware that I haven't tested the code, this is just a sample code that might help you achieve your goal.

// function which return how many days it should add based on the selection of the complexity custom field.
def daysToAdd
if (complexityFieldValue == "Simple") {
daysToAdd = 3
} else if (complexityFieldValue == "Average") {
daysToAdd = 7
} else if (complexityFieldValue == "Complex") {
daysToAdd = 14
} else {
return
}

// function that finds the final datetime adding n-days
def addDaysExcludingWeekends(startDate, days) {
Calendar cal = Calendar.getInstance()
cal.setTime(startDate)
while (days > 0) {
cal.add(Calendar.DAY_OF_MONTH, 1)
if (cal.get(Calendar.DAY_OF_WEEK) != Calendar.FRIDAY &&
cal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY &&
cal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
days--
}
}
return cal.getTime()
}

// calculated dueDate
def dueDate = addDaysExcludingWeekends(currentDate, daysToAdd)

// update the issue
issue.setCustomFieldValue(duedateField, dueDate)

 I hope it helps!

Best!

Megan D August 14, 2024

Thank you so much for the wright up and code! However this didn't end up working. Errors come up on the following snippets:

cal.setTime(startDate)

"Cannot find matching method java.util.Calendar#setTime(java.lang.Object)."

 

while (days>0) {

"Cannot find matching method java.lang.Object#compareTo(int)"

 

days--

"Cannot find matching method java.lang.Object#previous()"

 

def dueDate = addDaysExcludingWeekends(currentDate, daysToAdd)

"The varable [currentDate] is undeclared"

 

issue.setCustomFieldValue(duedateField, dueDate)

"The variable [dueDateField] is undeclared."

"Cannot find matching method com.atlassian.jira.issue.MutableIssue#setCustomFieldValue(java.lang.Object, javalang.Object)."

 

Any more help would be appreciated! Thanks again =)

 

 

Tuncay Senturk
Community Champion
August 19, 2024

Hi,

Sorry for the late response, I was away!

Did you add the import line for Calendar?

import java.util.Calendar

Also, could you please use this one?

def addDaysExcludingWeekends(Date startDate, int days) {
Calendar cal = Calendar.getInstance()
cal.setTime(startDate)
while (days > 0) {
cal.add(Calendar.DAY_OF_MONTH, 1)
if (cal.get(Calendar.DAY_OF_WEEK) != Calendar.FRIDAY &&
cal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY &&
cal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
days--
}
}
return cal.getTime()
}


// calculated dueDate
Date currentDate = new Date()
def dueDate = addDaysExcludingWeekends(currentDate, daysToAdd)

For the duedatefield problem, you have to change duedate definition 

def duedate = customFieldManager.getCustomFieldObjects(14233)

to duedateField

def duedateField = customFieldManager.getCustomFieldObjects(14233L)

 also, you have to replace other duedate usages with duedateField, as below

def duedateValue = dateFormat.parse(issue.getCustomFieldValue(duedateField).toString())

 I hope it helps

Tuncay Senturk
Community Champion
August 22, 2024

Hi @Megan D 

Have you had a chance to try the updated code?

Megan D September 3, 2024

Hi there, finally saw your reply - so it looks like it MIGHT work. Two things:

  • I didn't know where to put (from your last comment)
def duedateValue = dateFormat.parse(issue.getCustomFieldValue(duedateField).toString())

 

  • When I try to run the script (without the above line, lol), I get this error:

No signature of method: Script2042.addDaysExcludingWeekends() is applicable for argument types: (Date, null) values: [today's date/time, null]

Possible solutions:

addDaysExcludingWeekends(java.util.Date, int)

My current script is this (set in the Post Function of the transition)

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.util.DateFieldFormat
import com.atlassian.jira.timezone.TimeZoneManager
import java.util.Calendar
import java.util.Date*
import java.sql.Timestamp
import java.time.DayOfWeek
import java.time.LocalDateTime
import java.text.SimpleDateFormat

// gets "due date" custom field
def customFieldManager = ComponentAccessor.customFieldManager
def duedateField = customFieldManager.getCustomFieldObject(14233L)

//gets "request complexity" custom field
def complexityField = customFieldManager.getCustomFieldOjbect(14220)
def complexityValue = issue.getCustomFieldValue(complexityField).toString()


// function which return how many days it should add based on the selection of the complexity custom field.
def daysToAdd
if (complexityFieldValue == "Simple") {
daysToAdd = 3
} else if (complexityFieldValue == "Average") {
daysToAdd = 7
} else if (complexityFieldValue == "Complex") {
daysToAdd = 14
} else {
return
}

// calculated dueDate Date currentDate = new Date() def dueDate = addDaysExcludingWeekends(currentDate, daysToAdd)

// function that finds the final datetime adding n-days
def addDaysExcludingWeekends(Date startDate, int days) {
Calendar cal = Calendar.getInstance()
cal.setTime(startDate)
while (days > 0) {
cal.add(Calendar.DAY_OF_MONTH, 1)
if (cal.get(Calendar.DAY_OF_WEEK) != Calendar.FRIDAY &&
cal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY &&
cal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
days--
}
}
return cal.getTime()
}

// update the issue
issue.setCustomFieldValue(duedateField, dueDate)

 

Tuncay Senturk
Community Champion
September 4, 2024

Hello again, below is the usage of dueDateField and dueDateValue. Let me know if you have any problems

def duedateField = customFieldManager.getCustomFieldObjects(14233L)

def duedateValue = dateFormat.parse(issue.getCustomFieldValue(duedateField).toString())

def dueDate = addDaysExcludingWeekends(duedateValue, daysToAdd)

 

0 votes
Chris Melville
Contributor
September 3, 2024

You can use it as a post function also, just remove the event handling code, e.g.

IssueEvent issueEvent = event as IssueEvent
Issue issue = issueEvent.issue

and  

if (!issueEvent?.getChangeLog()?.getRelated("ChildChangeItem")?.find { it.field == complexityFieldName }) {
return
}
0 votes
Chris Melville
Contributor
September 3, 2024

Here is a script you can use.  Set it up as a listener.  Anytime your complexity field changes the duedate will be adjusted as you wish.  It also accommodates adding any holidays you might want to declare 'non-working' days.

 

import com.atlassian.jira.issue.Issue
import com.atlassian.jira.event.issue.IssueEvent
import java.sql.Timestamp
import java.text.SimpleDateFormat
import org.apache.log4j.Level
log.setLevel(Level.DEBUG)

IssueEvent issueEvent = event as IssueEvent
Issue issue = issueEvent.issue

def complexityFieldName = "Complexity"
if (!issueEvent?.getChangeLog()?.getRelated("ChildChangeItem")?.find { it.field == complexityFieldName }) {
return
}

def complexity = [
"Simple" : 3,
"Average" : 7,
"Complex" : 14
]

def complexityFieldValue = issue.getCustomFieldValue(complexityFieldName)?.value.toString()
if (!complexity.containsKey(complexityFieldValue)) {
log.debug("Complexity value is unknown: $complexityFieldValue")
return
}

Timestamp dueDate = issue.dueDate
Timestamp newDueDate = addOffset(dueDate, complexity[complexityFieldValue])
log.debug("Changing duedate from $dueDate to $newDueDate")
issue.update {
setDueDate {
set(newDueDate)
}
}

def Timestamp addOffset(date, int offset) {
def nonWorkingDays = [
Calendar.FRIDAY, Calendar.SATURDAY, Calendar.SUNDAY
]
def holidays = [
'01/01/2025', '01/02/2025', '01/03/2025', '01/04/2025', '01/05/2025'
]

Calendar cal = Calendar.getInstance()
cal.setTime(date)
int businessDayCount = 0
SimpleDateFormat fmt = new SimpleDateFormat('MM/dd/yyyy')
while (businessDayCount < offset) {
cal.add(Calendar.DATE, 1)
if (cal.get(Calendar.DAY_OF_WEEK) in nonWorkingDays || fmt.format(cal.getTime()) in holidays)
continue
businessDayCount++
}
return new Timestamp(cal.getTimeInMillis())
}

 

Suggest an answer

Log in or Sign up to answer