I have a data source using a Tag Historian Query with several boolean "Running" tags. My aim is to calculate running hours over a set time frame. I can do this using the "Duration On" aggregation mode but it gives me the result in seconds and I need this to display in hh:mm:ss format.

I believe the only way to achieve the result in hh:mm:ss format is by using a script data source but I am struggling to achieve the result. Any ideas?

Logging runtimes seems like a job for the PLC, but as far as purely converting seconds to hh.mm/mm.ss, here is mine. I'm sure there's a more efficient way to do it, but this works for me.

def toHHMMSS(val, hours, mins, secs):
'''
convert a value in hours, minutes, or seconds to a readable hours.minutes/minutes.seconds (hh.mm/mm.ss) format
Args:
val (double) : time value to convert
hours (bool) : time value is in hours
mins (bool) : time value is in minutes
secs (bool) : time value is in seconds
Returns:
result (double : time to display
result_label (string) : label for result (hh.mm or mm.ss))
'''
from math import floor
####convert any provided val to seconds####
#value provided in seconds
if secs:
val_seconds = val
#value provided in minutes
elif mins:
val_seconds = val*60.0
#value provided in hours
else:
val_seconds = val*60.0*60.0
####hours calculation####
#more than 1 full hour
if val_seconds > 60*60:
#calculate hours
val_hours = val_seconds/(60.0*60.0)
#get whole number of hours
whole_hours = floor(val_hours)
#get remaining number of minutes
rem_minutes = (val_hours - whole_hours)*60.0
#set whole and fractional results (hh.mm)
result_whole = whole_hours
result_rem = rem_minutes/100.0
result_label = 'hh.mm'
#less than 1 full hour
else:
####minutes calculation####
#more than 1 full minute
if val_seconds > 60:
#calculate minutes
val_minutes = val_seconds/60.0
#get whole number of minutes
whole_minutes = floor(val_minutes)
#get remaining number of seconds
rem_seconds = (val_minutes - whole_minutes)*60.0
#less than 1 full minute
else:
#no full minutes
whole_minutes = 0
#get remaining number of seconds
rem_seconds = val_seconds
#set whole and fractional results (hh.mm)
result_whole = whole_minutes
result_rem = rem_seconds/100.0
result_label = 'mm.ss'
#combine whole number with decimal
result = result_whole+result_rem
return result, result_label

You could pair the above with something like this general purpose mapColumn function for datasets, to update all the values in a particular column of the dataset as one operation:

You get less control over the boundary conditions, but you can also use our FormatUtil internal library to achieve the same result: