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 _Snapbytes_
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 _Snapbytes_
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 _Snapbytes_
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 _Snapbytes_
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