SAI VENKATESH
Kilo Patron

In many organizations, change management windows like freeze, blackout, and maintenance periods are very important to avoid risks during critical times. However, users can sometimes by mistaken select Planned Start Date or Planned End Date that fall within these restricted windows, which may lead to conflicts or issues during implementation.

To handle this, I added a client-side validation in ServiceNow that checks the selected dates and prevents users from submitting change requests.

 

We created two On Change Client Scripts—one for Planned Start Date and another for Planned End Date—and used a Script Include that is called from both client scripts.
 
On change Client Script : planned Start Date
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
    if (isLoading || newValue === '') {
        return;
    }

    if (g_form.getValue('type') == 'normal') {
        var ga = new GlideAjax("ChangeFreezeScheduleCheck");
        ga.addParam('sysparm_name', 'checkFreeze');
        ga.addParam('sysparm_start', g_form.getDisplayValue('start_date'));
        ga.addParam('sysparm_end', g_form.getDisplayValue('end_date'));
        ga.getXMLAnswer(function(response) {
            if (response == 'yes') {
                g_form.addInfoMessage("Planned start date provided is within the  Change Freeze Schedule. Please provide a date/time outside of this schedule.");
                g_form.setValue('start_date', '');
            } else if (response == 'no') {
                g_form.addInfoMessage("Planned end date provided is within the Change Freeze Schedule. Please provide a date/time outside of this schedule.");
                g_form.setValue('end_date', '');
            } else if (response == 'NA') {
                g_form.addInfoMessage("Planned dates provided are within the Change Freeze Schedule. Please provide a date/time outside of this schedule.");
                g_form.setValue('start_date', '');
                g_form.setValue('end_date', '');
            }
        });
    }
}

 On change Client Script : planned End Date

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
    if (isLoading || newValue === '') {
        return;
    }

    if (g_form.getValue('type') == 'normal') {
        var ga = new GlideAjax("ChangeFreezeScheduleCheck");
        ga.addParam('sysparm_name', 'checkFreeze');
        ga.addParam('sysparm_start', g_form.getDisplayValue('start_date'));
        ga.addParam('sysparm_end', g_form.getDisplayValue('end_date'));
        ga.getXMLAnswer(function(response) {
            if (response == 'yes') {
                g_form.addInfoMessage("Planned start date provided is within the Change Freeze Schedule. Please provide a date/time outside of this schedule.");
                g_form.setValue('start_date', '');
            } else if (response == 'no') {
                g_form.addInfoMessage("Planned end date provided is within the Change Freeze Schedule. Please provide a date/time outside of this schedule.");
                g_form.setValue('end_date', '');
            } else if (response == 'NA') {
                g_form.addInfoMessage("Planned dates provided are within the  Change Freeze Schedule. Please provide a date/time outside of this schedule.");
                g_form.setValue('start_date', '');
                g_form.setValue('end_date', '');
            }
        });
    }
}

 

Script Include:

var ChangeFreezeScheduleCheck = Class.create();
ChangeFreezeScheduleCheck.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    checkFreeze: function() {
        var start = this.getParameter('sysparm_start'); //Planned start date getting from change request
        if (!start) {
            return false;
        }
        var gdtStart = new GlideDateTime(start);

        var end = this.getParameter('sysparm_end'); //Planned end date getting from change request
        if (!end) {
            return false;
        }
        var gdtEnd = new GlideDateTime(end);

        var jsonOutput = [];

        var gr = new GlideRecord('cmn_schedule_span');
        gr.addQuery('schedule', 'Your Schedule');
        gr.query();

        while (gr.next()) {

            var startRaw = gr.getValue('start_date_time'); 
            var endRaw = gr.getValue('end_date_time'); 

			//Convert to usable GDT format
            var startGdt = new GlideDateTime(this.formatDate(startRaw));
            var endGdt = new GlideDateTime(this.formatDate(endRaw));

            jsonOutput.push({
                start: startGdt.getDisplayValue(),
                end: endGdt.getDisplayValue()
            });
        }

        var len = jsonOutput.length;

        var startNum = gdtStart.getNumericValue();
        var endNum = gdtEnd.getNumericValue();

        for (var i = 0; i < len; i++) {
            var startRange = new GlideDateTime(jsonOutput[i].start).getNumericValue();
            var endRange = new GlideDateTime(jsonOutput[i].end).getNumericValue();
            if (startNum >= startRange && startNum <= endRange) { //Change start time is between start and end of schedule
                return 'yes';
            } else if (endNum >= startRange && endNum <= endRange) { //Change end time is between start and end of schedule
                return 'no';
            } else if (startNum < startRange && endNum > endRange) { //Change start and end times span over start and end of schedule
                return 'NA';
            }
        }
    },

    formatDate: function(raw) { //Converts times on schedule entry from YYYYMMDDT000000Z to YYYY-MM-DD 00:00:00 format
        return raw.substring(0, 4) + "-" +
            raw.substring(4, 6) + "-" +
            raw.substring(6, 8) + " " +
            raw.substring(9, 11) + ":" +
            raw.substring(11, 13) + ":" +
            raw.substring(13, 15);
    },

    type: 'ChangeFreezeScheduleCheck'
});

 

 

Hopefully this will help others who are trying to handle similar validations.



Thanks and Regards

Sai Venkatesh

Version history
Last update:
2 hours ago
Updated by:
Contributors