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!


ScriptRunner - Get name of user who made last transition


I found a script that shows the amount of time an issue was in a status, i.e. 21 minutes "On Hold", 1 week "In Progress".

This is a duration template used.

I am wondering if I can modify this script OR would it be easier to create a new field and add a script to display the name of the user who made the last transition?

I am not sure what that script would look like if someone could assist with that?

1 answer

1 accepted

Suggest an answer

Log in or Sign up to answer
1 vote
Answer accepted
Radek Dostál
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.
Sep 20, 2021

If the current field returns "duration", then you cannot make it return anything other than that - time. Notice that the script probably returns a number (long). The 'duration' template then takes your script's value, and transforms it into a human-readable format.

You could switch it from duration to something generic such as text - and then format your current duration to a specific date format, alongside the user who did the last transition; OR, as you say, have 2 separate fields, one for duration, another for the user.

I am a bit confused though because if you have "duration", then it can only show a single duration. At the same time, you mention multiple statuses.

Can you paste the script in a code block so we know what it actually does?

Getting the user doing the last transition is not hard at all. It probably already traverses issue history, in a sorted way, so all you'd need to do is get the first(or last) changehistory record from the collection, depending on how it's sorted.

Hi @Radek Dostál ,


So it is multiple custom fields I created and shows the time an issue was in that status. I.e. - the script below shows how long it was "in progress" and I have a few others and just change the def inProgressName =

I did a few custom fields as I was not sure if you could combine it?


import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.history.ChangeItemBean

def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()

def inProgressName = "In Progress"

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


What I would like is to show the name of the user who made that transition and for how long it was in that status.


I know that you can see that on the Transitions tab on the screen but I cant export that information 

Radek Dostál
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.
Sep 21, 2021 • edited

Well, okay, I've tried to combine this so that it returns the "same" duration (a little different way to get there but it's the same data at the end of the day), along with who the first user to transition into the status is.


The main difference is that this returns String, therefore the field output template must be Text.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.changehistory.ChangeHistory
import com.atlassian.jira.issue.changehistory.ChangeHistoryManager
import com.atlassian.jira.issue.history.ChangeItemBean
import java.time.Duration

ChangeHistoryManager changeHistoryManager = ComponentAccessor.getChangeHistoryManager()

final String STATUS_NAME = "In Progress"

List<Long> rt = new LinkedList<>()
rt.add(0L) //So that the list is not empty as we're going to sum the elements at the end

//The username variable for when we find it in ChangeHistory
String username = null

Previously, this was using changeHistoryManager.getChangeItemBeans(issue, "status")
-- this returns ChangeItemBeans, however they do not have the "author" data on it
For this reason this is instead using changeHistoryManager.getChangeHistories(issue)
-- this returns us the history records, including the author, we just need to traverse the ChangeItemBeans per ChangeHistory

List<ChangeHistory> changeHistories = changeHistoryManager.getChangeHistories(issue)
for (ChangeHistory changeHistory : changeHistories.reverse()) { //reversed order going from most recent to oldest
List<ChangeItemBean> changeItemBeanList = changeHistory.getChangeItemBeans()
for (ChangeItemBean changeItemBean : changeItemBeanList) {
if (changeItemBean.getField() == "status") {
long timeDiff = System.currentTimeMillis() - changeItemBean.getCreated().getTime()
if (changeItemBean.getFromString() == STATUS_NAME) rt.add(-timeDiff)
if (changeItemBean.getToString() == STATUS_NAME) {
username = changeHistory.getUsername() //Not ideal as this var constantly gets updated, but.. we are afterall traversing all change histories in reverse, so

long total = (long) rt.sum()
Duration duration = Duration.ofMillis(total)

return total != 0L ? reformatDurationToString(duration) + ", "+username : null

String reformatDurationToString(Duration duration) {
// Normally, we don't need anything with dates. However, Jira by default uses 8h = 1d conversion, so if we are
// staying true to that, we just multiply the days by 3, as long as we also apply the same logic with hours
long days = duration.toDays() *3

// Again, using Jira's default 8h = 1d logic, we cannot just return e.g. 17 hours, because this effectively for Jira means, 2 days, 1 hour
// If we use just .toHours(), we can get e.g. 255 hours
// If we use .toHoursPart(), it effectively does % 24; meaning 15 hours; and we use this because we already have days so we just want remaining hours
int hours = duration.toHoursPart()
if (hours > 16) {
days = days +2
hours = hours % 8
else if (hours == 16) {
days = days +2
hours = 0
else if (hours > 8) {
hours = hours % 8
else if (hours == 8) {
hours = 0
else {
//nothing, if we're 0-8 then we are within 8h/1d time tracking

int minutes = duration.toMinutesPart()

if (days != 0L) return days+" days, "+hours+" hours, "+minutes+" minutes"
else if (hours != 0) return hours+" hours, "+minutes+" minutes"
else return minutes+" minutes"


And what this results in in the end is something along the lines of:





It can use maybe a change or two but, it does both, the duration and the user, as perhaps an example, albeit I think it can be optimized and shortened a bit.

If you prefer the 24hour per day format then it's just one function to modify a bit.


Alternatively, if you decide you want just the user, as a separate field, then we can optimize the ChangeHistory lookup a little, because it no longer requires to be reversed going from recent to old, so it can just find the first match instead:

String username = null
List<ChangeHistory> changeHistories = changeHistoryManager.getChangeHistories(issue)
for (ChangeHistory changeHistory : changeHistories) { //no longer need to reverse, we need first occurrence only
List<ChangeItemBean> changeItemBeanList = changeHistory.getChangeItemBeans()
for (ChangeItemBean changeItemBean : changeItemBeanList) {
if (changeItemBean.getField() == "status") {
if (changeItemBean.getToString() == STATUS_NAME) {
username = changeHistory.getUsername()
if (username != null) break
return username


I hope I'm not totally off here, if I understood this, or at least it's a step closer.

Like Alfira Merinova likes this

Hi @Radek Dostál , you have understood it perfectly...

Thank you so much! 


Hi @Radek Dostál , sorry to bother you again but can it be shortened to display the days and hours?

Minutes is not really needed. Thanks

AUG Leaders

Atlassian Community Events