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

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

Avatar

1 badge earned

Collect

Participate in fun challenges

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

Challenges
Coins

Gift kudos to your peers

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

Recognition
Ribbon

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!

Leaderboard

Come for the products,
stay for the community

The Atlassian Community can help you and your team get more value out of Atlassian products and practices.

Atlassian Community about banner
4,463,682
Community Members
 
Community Events
176
Community Groups

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

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
import java.util.stream.IntStream

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())
else
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;

private static final long WORKING_HOURS_PER_DAY = WORK_HOUR_END - WORK_HOUR_START;
private static final long WORKING_SECONDS_PER_DAY = WORKING_HOURS_PER_DAY * SECONDS_PER_HOUR;

public int getWorkingSecondsSince(final Timestamp startTime) {
Timestamp now = Timestamp.from(Instant.now());
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))}
.count() * WORKING_SECONDS_PER_DAY ;

// 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
Vishwas Rising Star 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.

https://community.atlassian.com/t5/Marketplace-Apps-Integrations/Ageing-Calculated-Field-excluding-weekends-using-JMCF/qaq-p/594228

 

Regards,

Vishwas

Suggest an answer

Log in or Sign up to answer
TAGS

Atlassian Community Events