ServiceNow SLA - Complex Business Hours, Holidays and Weekend Rules
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
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 Computing | Incident | P1 | 3 Hours | 3 Hours | 3 Hours | 3 Hours |
| Personal Computing | Incident | P2 | 8 Hours | 8 Hours | 8 Hours | 8 Hours |
| Personal Computing | Incident | P3 | 12 Hours | 12 Hours | 12 Hours | 12 Hours |
| Multimedia | Incident | P1 | 4 Hours | 4 Hours | 4 Hours | 4 Hours from Saturday/Holiday End |
| Multimedia | Incident | P2 | 6 Hours | 6 Hours | 6 Hours | End of Next Working Day |
| Multimedia | Incident | P3 | 24 Hours | 24 Hours | End of Next Working Day | End of Next Working Day |
| Telephony | Incident | P1 | 3 Hours | 3 Hours | 3 Hours | 3 Hours from Saturday/Holiday End |
| Telephony | Incident | P2 | 8 Hours | 8 Hours | 8 Hours | 8 Hours |
| Telephony | Incident | P3 | 12 Hours | 12 Hours | 12 Hours | 12 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!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
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?