ServiceNow SLA - Complex Business Hours, Holidays and Weekend Rules

SapirY
Tera Contributor

Hi everyone,

I'm implementing SLAs for the Incident table in ServiceNow and I'm looking for the best practice for handling complex SLA calculations.

Our SLA rules depend on:

  • Business service
  • Priority
  • Business hours
  • Off-business hours
  • Fridays
  • Holidays
  • Saturdays
  • Variable end time for Saturday/Holiday (depending on the season)

One important requirement is that Holiday schedules cannot simply be excluded using a Schedule, because SLA time should sometimes continue counting during holidays.

For example:

  • An Incident is opened on Holiday Eve at 3:30 PM.
  • The SLA is 4 hours.
  • The expected Due Date is 7:30 PM, even if the holiday starts at 4:00 PM.

On the other hand, for some services the requirement is different:

  • If an Incident is opened between Friday 4:00 PM and Saturday holiday/weekend end, the SLA should start only after Saturday ends, and then count the required SLA hours.

Saturday ends at:

  • April – October: 8:00 PM
  • November – March: 6:00 PM

Some SLAs also have a target of End of the Next Working Day, where a working day is defined as any day that is not Saturday or a Holiday, ending at 6:00 PM.

Has anyone implemented a similar requirement?

Would you recommend:

  • Multiple SLA Definitions?
  • Relative Duration Scripts?
  • Custom SLA Calculator / Script Include?
  • Another best-practice approach?

Below is the business matrix we need to implement.

Business Service Ticket Type Priority Business Hours (07:00-18:00) Off Hours (18:00-07:00 / Saturday End → 07:00) Friday / Holiday Eve (07:00-16:00) Saturday / Holiday (From 16:00 until Saturday/Holiday End)

Personal ComputingIncidentP13 Hours3 Hours3 Hours3 Hours
Personal ComputingIncidentP28 Hours8 Hours8 Hours8 Hours
Personal ComputingIncidentP312 Hours12 Hours12 Hours12 Hours
MultimediaIncidentP14 Hours4 Hours4 Hours4 Hours from Saturday/Holiday End
MultimediaIncidentP26 Hours6 Hours6 HoursEnd of Next Working Day
MultimediaIncidentP324 Hours24 HoursEnd of Next Working DayEnd of Next Working Day
TelephonyIncidentP13 Hours3 Hours3 Hours3 Hours from Saturday/Holiday End
TelephonyIncidentP28 Hours8 Hours8 Hours8 Hours
TelephonyIncidentP312 Hours12 Hours12 Hours12 Hours

Notes:

  • End of Next Working Day = the nearest working day that is not Saturday or a Holiday, ending at 6:00 PM.
  • Saturday End:
    • April – October: 8:00 PM
    • November – March: 6:00 PM

I'd appreciate any recommendations or examples of how you would implement this in ServiceNow while following best practices.

Thank you!

2 REPLIES 2

yashkamde
Giga Sage

Hello @SapirY ,

 

As per your requirement,

firstly don't try to force this into Schedule records. Use schedules only for the parts that are static (e.g defining Business Hours 07:00–18:00 Mon–Thu" and "Friday 07:00–16:00" as reference calendars), and drive the actual due-date math with script.

 

I will recommend Script-driven calculation, minimal SLA Definitions

1) Use the priority and time as inputs to a shared calculator, not as separate definitions.

 

2) Also you can create a table like u_sla_matrix:

business_service, ticket_type, priority, business_hours_rule, off_hours_rule, friday_holiday_eve_rule, saturday_holiday_rule..

 

bcz when the business changes 4 hrs to 5 hrs next quarter, someone should edit a record, not a script.

 

3) Further create 2 script include :

// HolidayCalendarUtil — pure calendar/date math, no matrix logic
var HolidayCalendarUtil = Class.create();
HolidayCalendarUtil.prototype = {
    initialize: function() {},

    isHoliday: function(gdt) { /* lookup custom holiday table */ },
    isSaturday: function(gdt) { return gdt.getDayOfWeekLocalTime() == 7; },
    isFridayOrHolidayEve: function(gdt) { /* Friday, or day before a holiday */ },

    // April-Oct = 8PM, Nov-Mar = 6PM
    getPeriodEndTime: function(gdt) {
        var month = gdt.getMonthLocalTime(); // 1-12
        var endHour = (month >= 4 && month <= 10) ? 20 : 18;
        var end = new GlideDateTime(gdt);
        end.setDisplayValue(gdt.getDate() + ' ' + endHour + ':00:00');
        return end;
    },

    getNextWorkingDayEnd: function(gdt) {
        var d = new GlideDateTime(gdt);
        d.addDaysLocalTime(1);
        while (this.isSaturday(d) || this.isHoliday(d)) {
            d.addDaysLocalTime(1);
        }
        d.setDisplayValue(d.getDate() + ' 18:00:00');
        return d;
    },

    type: 'HolidayCalendarUtil'
};

 

// SLADueDateCalculator — reads matrix, picks bucket, delegates math
var SLADueDateCalculator = Class.create();
SLADueDateCalculator.prototype = {
    initialize: function() {
        this.cal = new HolidayCalendarUtil();
    },

    calculateDueDate: function(taskSlaGR) {
        var task = taskSlaGR.task.getRefRecord();
        var start = new GlideDateTime(taskSlaGR.start_time);
        var matrixRow = this._getMatrixRow(task);   // service + priority + ticket_type lookup
        var bucket = this._resolveBucket(start);     // business_hours | off_hours | friday_holiday_eve | saturday_holiday
        var rule = matrixRow[bucket + '_rule'];

        switch (rule.type) {
            case 'FIXED_DURATION':
                var due = new GlideDateTime(start);
                due.addSeconds(rule.hours * 3600);
                return due;

            case 'FIXED_FROM_PERIOD_END':
                var periodEnd = this.cal.getPeriodEndTime(start);
                periodEnd.addSeconds(rule.hours * 3600);
                return periodEnd;

            case 'END_OF_NEXT_WORKING_DAY':
                return this.cal.getNextWorkingDayEnd(start);
        }
    },

    type: 'SLADueDateCalculator'
};

 

 

And Trigger that using BR :

var calc = new SLADueDateCalculator();
    var due = calc.calculateDueDate(current);
    current.planned_end_time = due;
    current.duration = GlideDateTime.subtract(current.start_time.getGlideObject(), due);

 

If my response helped mark as helpful and accept the solution.

SapirY
Tera Contributor

Thank you for the detailed explanation!

I really like the idea of separating the calendar logic from the SLA calculation.

However, I'd prefer not to create a custom matrix table for this requirement.

Do you have any suggestions for implementing this without creating a custom table?