Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

how to SUM of multiple duration field?

lucky24
Tera Contributor

Hi Team,

In metrics definition I am getting multiple record when I am changing same value in multiple time (changing value awaiting caller again and again)

find_real_file.png

 

So now I want to sum these duration and have to store in custom field of incident,

I am trying with below code but not get success 

var duration = new GlideDuration(0);
var mi = new GlideRecord("metric_instance");
mi.addQuery("id", current.sys_id);
mi.addQuery("definition", "fc47ec1d2f1341105d0d56e62799b64e");
mi.addQuery("value", "Awaiting Caller");
mi.query();
mi.getRowCount();
// while(mi.next()){
var dur = new GlideDuration();
dur.setValue(mi.getValue('duration'));
duration = duration.add(dur);

// }
current.u_pause_duration= duration.getDisplayValue();
current.u_total_hour=duration;
gs.addInfoMessage(duration.getDisplayValue());
gs.addInfoMessage(mi.getRowCount());
current.update();

 

So how can we achieve it please help me here?

 

please help me here.

 

2 REPLIES 2

Mahesh23
Mega Sage

Hi,

Try below code

var dur = new DurationCalculator();

dur =mi.duration.dateNumericValue();

mi.duration.setDateNumericValue(dur);

Hope this can help you!

ThorS
Tera Expert

I was able to run a background script to perform the summary and provide an output; additionally the script will update your base records with the duration for each value in the field being durat(ed?). 

You should be able to use this for your business rule:

(function() {
    // === Configuration ===
    var metricDefSysId = '1234'; // Replace with your metric_definition sys_id
    var baseTableName = 'x_custombasetable'; // your base table name (lowercase)
   
    // Helper function to convert duration string (e.g., '1970-01-12 00:05:59') to seconds
    function durationStringToSeconds(durationStr) {
        if (!durationStr)
            return 0;
       
        var gdt = new GlideDateTime(durationStr);
        var epoch = new GlideDateTime('1970-01-01 00:00:00');
        var diffMs = gdt.getNumericValue() - epoch.getNumericValue();
        return Math.floor(diffMs / 1000);
    }
   
    // Maps to hold data
    var aggregatedData = {};    // { recordSysId: { _record_number: string, state1: durationDays, ... } }
    var uniqueStates = {};      // { stateName: true }
    var unmatchedIds = [];      // to log sys_ids not found in base table
   
    // Query metric_instance for the metric definition
    var gr = new GlideRecord('metric_instance');
    gr.addQuery('definition', metricDefSysId);
    gr.query();
   
    while (gr.next()) {
        var recordSysId = gr.getValue('id'); // Assuming this is sys_id of base record
        if (!recordSysId) {
            gs.info('metric_instance ' + gr.getValue('sys_id') + ' missing id field');
            continue;
        }
       
        // Parse duration string to seconds
        var rawDuration = gr.getValue('duration');
        var durationSeconds = durationStringToSeconds(rawDuration);
       
        // Convert seconds to days (float)
        var durationDays = durationSeconds / 86400;
       
        // Initialize aggregation object if needed
        if (!aggregatedData[recordSysId]) {
            aggregatedData[recordSysId] = {
                _record_number: null
            };
           
            // Get base record by sys_id
            var recGr = new GlideRecord(baseTableName);
            if (recGr.get(recordSysId)) {
                aggregatedData[recordSysId]._record_number = recGr.getValue('number') || 'UNKNOWN_NUMBER';
            } else {
                aggregatedData[recordSysId]._record_number = 'UNKNOWN';
                unmatchedIds.push(recordSysId);
            }
        }
       
        // Use 'value' field for the state
        var stateValue = gr.getValue('value') || 'UNKNOWN_STATE';
        uniqueStates[stateValue] = true;
       
        if (!aggregatedData[recordSysId][stateValue]) {
            aggregatedData[recordSysId][stateValue] = 0;
        }
        aggregatedData[recordSysId][stateValue] += durationDays;
    }
   
    // Build CSV header
    var stateList = Object.keys(uniqueStates).sort();
    var csvHeader = ['Record Number'].concat(stateList.map(function(s){ return '"' + s + '"'; })).join(',');
   
    var csvRows = [];
    csvRows.push(csvHeader);
   
    for (var recId in aggregatedData) {
        if (!aggregatedData.hasOwnProperty(recId)) continue;
        var recData = aggregatedData[recId];
        var row = [];
        row.push('"' + (recData._record_number || '') + '"');
       
        for (var i = 0; i < stateList.length; i++) {
            var st = stateList[i];
            var dur = recData[st] || 0;
            // Round to 2 decimals
            dur = Math.round(dur * 100) / 100;
            row.push(dur);
        }
       
        csvRows.push(row.join(','));
    }
   
    var csvOutput = csvRows.join('\n');
   
    gs.info('=== Duration (in days) per State per Custom Base Record ===');
    gs.info(csvOutput);
   
    if (unmatchedIds.length > 0) {
        gs.info('=== Unmatched sys_ids (not found in base table) ===');
        unmatchedIds.forEach(function(id) {
            gs.info(id);
        });
    }

// === Map state names to base record duration field names ===
// Adjust these mappings to your actual state names and corresponding field names on x_custombasetable
var stateToFieldMap = {
    
    "Work in Progress": "duration_work_in_progress",
    "Complete": "duration_complete"
   


    // Add all your state-to-field mappings here
};

// Now update each base record with summed durations
for (var recSysId in aggregatedData) {
    if (!aggregatedData.hasOwnProperty(recSysId)) continue;
    var recData = aggregatedData[recSysId];

    // Load the base record
    var recGr = new GlideRecord(baseTableName);
    if (recGr.get(recSysId)) {
        // For each state, set the corresponding duration field
        for (var stateName in stateToFieldMap) {
            if (!stateToFieldMap.hasOwnProperty(stateName)) continue;

            var fieldName = stateToFieldMap[stateName];
            var durationDays = recData[stateName] || 0;

            // Update the field with rounded duration (days)
            recGr.setValue(fieldName, Math.round(durationDays * 100) / 100);
        }
        recGr.update();
    }
}

})();