Auto-Close Tasks within Business Hours With GlideSchedule API
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-07-2025 06:38 AM
Have you ever wanted to automatically close tasks in ServiceNow only after a specific number of business days, based on your organization’s working hours and holiday schedule?
In this blog post, I’ll walk you through a real-world script I built to automatically close resolved Incident Tasks or Any Record after a configurable number of business days — not just calendar time. This script uses the GlideSchedule API to accurately track time inside working hours only (e.g., 8 AM – 4 PM, Monday–Friday, excluding holidays).
Use Case:
Close tasks that are in the Resolved state for more than X business days (configured via system property) based on a defined working schedule.
For example:
A task resolved on Friday at 4 PM will close the following Wednesday at 4 PM, assuming an 8–4, Monday–Friday schedule.
How to Implement This Script
You can implement this script in multiple ways depending on how you'd like it to run:
Scheduled Script Execution (Recommended)
Run it daily or hourly using a Scheduled Job in the background.Custom Scheduled Business Rule (Like Incident Auto-Close)
Replicate the behavior of the OOB Incident Auto-Close mechanism by:Creating a Business Rule that is triggered based on a schedule Time.
- Scheduled Trigger - Flow Designer.
Script Explained:
function autoCloseTask() {
var endDate = new GlideDateTime(); // Fetch current date & Time to compare
var scheduleId = 'Sys_Id'; // your actual schedule sys_id (e.g. 8-4, UK M-F with holidays)
var schedule = new GlideSchedule(scheduleId);
var diffHours; // Stores the Business Hours schedule to convert total elapsed hours into business days for Auto-Close evaluation.
var scheduleSpan = new GlideRecord("cmn_schedule_span");
/* Fetch Schedule Entry Details for a Given Schedule. Retrieve the Schedule Entries (from the cmn_schedule_span table) associated with a specific Schedule (e.g., "8-4", "UK M–F with holidays") by including only the following details: Start Date,End Date,Business Hours. This script queries the relevant schedule by name, then fetches and lists its associated time spans with relevant scheduling information. */
scheduleSpan.addQuery("schedule", scheduleId);
scheduleSpan.query();
if (scheduleSpan.next()) {
var startTime = scheduleSpan.start_date_time.getDisplayValue();
var endTime = scheduleSpan.end_date_time.getDisplayValue();
var startTimeDiff = new GlideDateTime(startTime);
var endTimeDiff = new GlideDateTime(endTime);
var diffMillis = endTimeDiff.getNumericValue() - startTimeDiff.getNumericValue(); // difference in milliseconds
diffHours = diffMillis / (1000 * 60 * 60); // convert to hours
}
if (schedule.isInSchedule(endDate)) { // checking the current day is on the schedule
var ps = gs.getProperty('pass the Property which will Return No.of Days'); //Fetching Auto Close property value in days
var pn = parseInt(ps);
var gr = new GlideRecord('Incident');
gr.addQuery('state', 'Resolved');
gr.addNotNullQuery('resolved');
gr.query();
while (gr.next()) {
var resolvedDate = gr.resolved;
var startDate = new GlideDateTime(resolvedDate);
var durationDiff = schedule.duration(startDate, endDate); // Determines the elapsed time in the schedule between two date time values using the timezone of the schedule
var timeString = durationDiff.getDurationValue();
// e.g The returned value will be in the format "1 00:24:18", representing total hours converted to either {Days:Hours:Minutes:Seconds} or {Hours:Minutes:Seconds} format; for example, 1 00:24:18 equals 24.4 hours, which is approximately 3.05 days based on your Business schedule.
// Parse the duration string into days, hours, minutes, seconds.
var dayPart = 0;
var hourPart = 0;
var minutePart = 0;
var secondPart = 0;
// Converting "1 00:24:18" or "00:24:18" into total hours.
if (timeString && timeString.indexOf(" ") > -1) {
// Case: contains days
var parts = timeString.split(" ");
dayPart = parseInt(parts[0], 10);
var timeParts = parts[1].split(":");
hourPart = parseInt(timeParts[0], 10);
minutePart = parseInt(timeParts[1], 10);
secondPart = parseInt(timeParts[2], 10);
} else if (timeString && timeString.indexOf(":") > -1) {
// Case: only time (no days)
var timeParts = timeString.split(":");
hourPart = parseInt(timeParts[0], 10);
minutePart = parseInt(timeParts[1], 10);
secondPart = parseInt(timeParts[2], 10);
}
// Convert to total hours (can use float if needed)
var totalHours = (dayPart * 24) + hourPart + (minutePart / 60) + (secondPart / 3600);
//converts this '1 00:24:18' value into hours
totalHours = Math.round(totalHours * 100) / 100;
// Round to 2 decimal places (optional)
var totalDays = (totalHours / parseInt(diffHours));
totalDays.toFixed(2);
// Converting total hours to no.of days based on 8hrs business duration.
if (totalDays >= pn) { //Compare totalHours value with property value
gr.state = 'Closed'; // state is setting to closed
gr.active = false;
gr.update();
}
}
}
}
This script was built out of a real-world need — to ensure tasks are closed only after the appropriate amount of working time has passed, not just based on 24hours on the clock.
Hope this helps you or your team automate similar processes in a schedule-aware, business-friendly way!
Let me know your thoughts, improvements, or how you’d extend this.
- 649 Views
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-07-2025 06:41 AM
Really helpful
Senior Lead Consultant, Kaptius
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-26-2025 03:08 AM
Really helpful for this content