Are you in the loop? Keep up with the latest by making sure you're subscribed to Community Announcements. Just click Watch and select Articles.

Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Earn badges and make progress

You're on your way to the next level! Join the Kudos program to earn points and save your progress.

Deleted user Avatar
Deleted user

Level 1: Seed

25 / 150 points

Next: Root


1 badge earned


Participate in fun challenges

Challenges come and go, but your rewards stay with you. Do more to earn more!


Gift kudos to your peers

What goes around comes around! Share the love by gifting kudos to your peers.


Rise up in the ranks

Keep earning points to reach the top of the leaderboard. It resets every quarter so you always have a chance!


Scripts Groove showing how long the task is in a specific status

Hello! I am new to Groove.
Please help me write the script Groove showing how long the task is in a specific status.
Only to display not the actual time - 24/7 A how working hours 5/8.

The code below will display the time 24/7. What should be the code to display the time in 5/8 format?
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.history.ChangeItemBean

def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()

def inProgressName = "X"

List<Long> rt = [0L]
def changeItems = changeHistoryManager.getChangeItemsForField(issue, "status")
changeItems.reverse().each { ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.getTime()
if (item.fromString == inProgressName) {
rt << -timeDiff
if (item.toString == inProgressName) {
rt << timeDiff

def total = rt.sum() as Long
return (total / 1000 ) as long ?: 0L  


PS. I am trying to configure the display of this functionality through (JMCF) Calculated (scripted) Duration Field

2 answers

0 votes
David Fischer _Appfire_
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
Jan 18, 2022

Hi @smorozov ,

you can use the following code, where you'll need to update the Status name (statusName), work hours (WORK_HOUR_START, WORK_HOUR_END), and time zone in which the work hours are defined (timeZone):

import com.atlassian.jira.issue.history.ChangeItemBean
import org.joda.time.DateTime
import org.joda.time.DateTimeZone

import java.sql.Timestamp
import java.time.*
import java.time.temporal.ChronoUnit

final String statusName = "To Do" //adjust for the status you want
final List<ChangeItemBean> changeItems = issue.getFieldHistory("status")
if (changeItems.size() == 0) //issue status has never changed
if (issue.get("status").name == statusName)
return workingSecondsBetween(new Date().getTime(), issue.getCreated().getTime())
return null;
long totalTime = 0L;
Long startTime = null;
//iterate over changes
for (ChangeItemBean changeItemBean : changeItems) {
if (changeItemBean.getFromString() == statusName) {
if (startTime == null) //this must have been the starting status
startTime = issue.getCreated().getTime();
totalTime += workingSecondsBetween(changeItemBean.getCreated().getTime(), startTime);
startTime = null;
if (changeItemBean.getToString() == statusName) {
startTime = changeItemBean.getCreated().getTime();
if (startTime != null)
totalTime += workingSecondsBetween(new Date().getTime(), startTime); //we are currently in the requested status
return totalTime

public class WorkingMinutesCalculator {
private static final int WORK_HOUR_START = 8; //first working hour
private static final int WORK_HOUR_END = 16; //last working hour (work ends at the end of this hour)
private static final long SECONDS_PER_HOUR = 3600;


public int getWorkingSecondsSince(final Timestamp startTime) {
Timestamp now = Timestamp.from(;
return getWorkingSeconds(startTime, now);

public int getWorkingSeconds(final Timestamp startTime, final Timestamp endTime) {
if (null == startTime || null == endTime) {
throw new IllegalStateException();
if (endTime.before(startTime)) {
return 0;

LocalDateTime from = startTime.toLocalDateTime();
LocalDateTime to = endTime.toLocalDateTime();

LocalDate fromDay = from.toLocalDate();
LocalDate toDay = to.toLocalDate();

int allDaysBetween = (int) (ChronoUnit.DAYS.between(fromDay, toDay) + 1);
long allWorkingSeconds = IntStream.range(0, allDaysBetween)
.filter{i -> isWorkingDay(from.plusDays(i))}

// from - working_day_from_start
long tailRedundantSeconds = 0;
if (isWorkingDay(from)) {
if (isWorkingHours(from)) {
tailRedundantSeconds = Duration.between(fromDay.atTime(WORK_HOUR_START, 0), from).toSeconds();
} else if (from.getHour() > WORK_HOUR_START) {
tailRedundantSeconds = WORKING_SECONDS_PER_DAY;

// working_day_end - to
long headRedundanSeconds = 0;
if (isWorkingDay(to)) {
if (isWorkingHours(to)) {
headRedundanSeconds = Duration.between(to, toDay.atTime(WORK_HOUR_END, 0)).toSeconds();
} else if (from.getHour() < WORK_HOUR_START) {
headRedundanSeconds = WORKING_SECONDS_PER_DAY;
return (int) (allWorkingSeconds - tailRedundantSeconds - headRedundanSeconds);

private boolean isWorkingDay(final LocalDateTime time) {
return time.getDayOfWeek().getValue() < DayOfWeek.SATURDAY.getValue();

private boolean isWorkingHours(final LocalDateTime time) {
int hour = time.getHour();
return WORK_HOUR_START <= hour && hour <= WORK_HOUR_END;

long workingSecondsBetween(long to, long from) {
//to and from are Unix time in the system time zone (not UTC)
final DateTimeZone timeZone = DateTimeZone.forID("America/Chicago") //adjust for the time zone you want
DateTime fromDt = new DateTime(from + (new Date(from)).getTimezoneOffset()*60000, timeZone)
DateTime toDt = new DateTime(to + (new Date(to)).getTimezoneOffset()*60000, timeZone)
return (new WorkingMinutesCalculator()).getWorkingSeconds(new Timestamp(fromDt.toLocalDateTime().getLocalMillis()), new Timestamp(toDt.toLocalDateTime().getLocalMillis()))
0 votes
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.
Jan 18, 2022

Hey @smorozov 

You can check out this link, JMCF field rite ? there is a code in the answer for your case. You may have to check and modify if requried.




Suggest an answer

Log in or Sign up to answer
AUG Leaders

Atlassian Community Events