Create a Catalog Client Script to Ensure Entered Date is Not Before Next Business Date

jmiskey
Kilo Sage

I have a Catalog Item where I am trying to create an onChange Catalog Client Script that ensures that the selected date is NOT before the next Business Date.  So, if they enter a date today, it cannot be before tomorrow's date (since tomorrow is not a weekend).

 

I had never used CoPilot before, and thought I would give it a shot to see if it could write the script for me.  Much to my surprise, it came up with code that works MOST of the time.  It just doesn't work if they choose tomorrow's date.  I added an alert to my code, and I think I see the issue.  I think it might be due to the GMT offset of 4 hours for our system.

 

Here is the code that it came up with (after I amended it to reflect my field name and added my alert):

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

  // Parse the entered date
  var enteredDate = new Date(newValue);
  enteredDate.setHours(0, 0, 0, 0); // Normalize time
  // Get today's date
  var today = new Date();
  today.setHours(0, 0, 0, 0);
  // Calculate the next business day
  var nextBusinessDay = new Date(today);
  nextBusinessDay.setDate(today.getDate() + 1);
  // Skip weekends
  while (nextBusinessDay.getDay() === 0 || nextBusinessDay.getDay() === 6) {
    nextBusinessDay.setDate(nextBusinessDay.getDate() + 1);
  }

  // Compare entered date with next business day
  alert('Entered Date: ' + enteredDate + '\n' + 'Next Business Day: ' + nextBusinessDay);
  if (enteredDate < nextBusinessDay) {
	alert('Date must be on or after the next business day!');
    g_form.setValue('u_check_due_date', '');
  }
   
}

and here is the alert I get when I choose tomorrow's date (2025-07-24) in my "u_check_due_date" field:

jmiskey_0-1753302907223.png

 

As you can see, if erroneously is changing my entered date to 2025-07-23, presumably when it is trying to remove the time component. 

 

Can anyone fix the code so that it does not do that, and functions properly?

 

Thanks

 

1 ACCEPTED SOLUTION

Ankur, I did some deep digging yesterday after I posted this, and found that we had done this once a long time ago, using a GlideAjax call very similar to your post.

 

Here is out Catalog Client Script:

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

	//Ensure Check Due Date is not any sooner than next Business Day
	var cdate = g_form.getValue('u_check_due_date');  //get entered Check Due Date
	var sdate = new Date();  //start date is current date/time  
	var ndays = 1;  //next business day

	var ajax = new GlideAjax('global.BusinessDateUtils');  
	ajax.addParam('sysparm_name','getBusinessDate');  
	ajax.addParam('sysparm_startdate', sdate);  
	ajax.addParam('sysparm_numdays', ndays); 
	ajax.getXML(doSomething);  

	function doSomething(response){  
		var answer = response.responseXML.documentElement.getAttribute("answer");  
		//Make sure Check Due Date is on or after next Business Date
		if (answer > cdate) {
			alert("You must select a date on or after next Business Day");
			g_form.setValue('u_check_due_date','');
		}
	}

}

and here is the Script Include we created for it year ago.  One nice feature is that you feed in the number of business days you want as a parameter (so it is not hard-coded in the function).  So it is dynamic and can be used for any number of business days:

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

	//Calculate business date from starting date and number of days (uses Weekdays plus Holidays calendar)
	getBusinessDate: function(){
		var startDate = this.getParameter('sysparm_startdate');
		var numDays = this.getParameter('sysparm_numdays');

		//var gdt = new GlideDateTime();
		var gdt = startDate;
		var dc = new DurationCalculator();
		dc.setSchedule('8746beb20ffb9a00e3b522d8b1050ebf'); //Weekdays excluding holidays schedule
		dc.setStartDateTime(gdt);
		dc.calcDuration(24*3600*numDays); //1 business day = 24 hours

		var edt= new GlideDateTime(dc.getEndDateTime());
		edt = edt.toString().split(' ');
		var dt = edt[0];
		
		return dt;
	},	

	type: 'BusinessDateUtils'
});

View solution in original post

8 REPLIES 8

Ankur, I did some deep digging yesterday after I posted this, and found that we had done this once a long time ago, using a GlideAjax call very similar to your post.

 

Here is out Catalog Client Script:

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

	//Ensure Check Due Date is not any sooner than next Business Day
	var cdate = g_form.getValue('u_check_due_date');  //get entered Check Due Date
	var sdate = new Date();  //start date is current date/time  
	var ndays = 1;  //next business day

	var ajax = new GlideAjax('global.BusinessDateUtils');  
	ajax.addParam('sysparm_name','getBusinessDate');  
	ajax.addParam('sysparm_startdate', sdate);  
	ajax.addParam('sysparm_numdays', ndays); 
	ajax.getXML(doSomething);  

	function doSomething(response){  
		var answer = response.responseXML.documentElement.getAttribute("answer");  
		//Make sure Check Due Date is on or after next Business Date
		if (answer > cdate) {
			alert("You must select a date on or after next Business Day");
			g_form.setValue('u_check_due_date','');
		}
	}

}

and here is the Script Include we created for it year ago.  One nice feature is that you feed in the number of business days you want as a parameter (so it is not hard-coded in the function).  So it is dynamic and can be used for any number of business days:

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

	//Calculate business date from starting date and number of days (uses Weekdays plus Holidays calendar)
	getBusinessDate: function(){
		var startDate = this.getParameter('sysparm_startdate');
		var numDays = this.getParameter('sysparm_numdays');

		//var gdt = new GlideDateTime();
		var gdt = startDate;
		var dc = new DurationCalculator();
		dc.setSchedule('8746beb20ffb9a00e3b522d8b1050ebf'); //Weekdays excluding holidays schedule
		dc.setStartDateTime(gdt);
		dc.calcDuration(24*3600*numDays); //1 business day = 24 hours

		var edt= new GlideDateTime(dc.getEndDateTime());
		edt = edt.toString().split(' ');
		var dt = edt[0];
		
		return dt;
	},	

	type: 'BusinessDateUtils'
});

@jmiskey 

I believe I also shared a working solution with that link, you can simply enhance.

As per new community feature you can mark multiple responses as correct.

If my response helped please mark it correct as well so that it benefits future readers.

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

@jmiskey 

Any update to this?

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

Yes, I already marked the solution I used a while back.  We found some code that we had used for this many years ago that still works well. 

 

While there were some similiarities in the link you provided, there were also some notable differences (i.e. it talks about using Schedules, which we did not want to do).  So it did not do exactly what we were looking for.  I did mark it as helpful though.