I
was recently asked to help a colleague figure out some date calculations based on a schedule. The requirement was to calculate a future date based on the existing value of a date/time field. I decided to document this solution (and come up with a solution for a similar problem…date addition from the current date/time based on a schedule). Working with dates and schedules can really be a pain if you don’t have good examples to work from so hopefully these help somebody at some point. Read on for the full scripts.
Add time based on schedule to current time
//Get a schedule by name to calculate duration
var schedRec = new GlideRecord('cmn_schedule');
schedRec.get('name', '8-5 weekdays');
if (typeof GlideSchedule != 'undefined')
var sched = new GlideSchedule(schedRec.sys_id);
else
var sched = new Packages.com.glide.schedules.Schedule(schedRec.sys_id);
//Get the current date/time in correct format for duration calculation
var currentDateTime = new GlideDateTime();
currentDateTime.setDisplayValue(gs.nowDateTime());
//Set the amount of time to add (in seconds)
var timeToAdd = 86400;
durToAdd = new GlideDuration(timeToAdd*1000);
var newDateTime = sched.add(currentDateTime, durToAdd, '');
//Set the 'requested_by_date' field to the new date/time
current.requested_by_date = newDateTime;
var schedRec = new GlideRecord('cmn_schedule');
schedRec.get('name', '8-5 weekdays');
if (typeof GlideSchedule != 'undefined')
var sched = new GlideSchedule(schedRec.sys_id);
else
var sched = new Packages.com.glide.schedules.Schedule(schedRec.sys_id);
//Get the current date/time in correct format for duration calculation
var currentDateTime = new GlideDateTime();
currentDateTime.setDisplayValue(gs.nowDateTime());
//Set the amount of time to add (in seconds)
var timeToAdd = 86400;
durToAdd = new GlideDuration(timeToAdd*1000);
var newDateTime = sched.add(currentDateTime, durToAdd, '');
//Set the 'requested_by_date' field to the new date/time
current.requested_by_date = newDateTime;
Add time based on schedule to current field value
//Get a schedule by name to calculate duration
var schedRec = new GlideRecord('cmn_schedule');
schedRec.get('name', '8-5 weekdays');
if (typeof GlideSchedule != 'undefined')
var sched = new GlideSchedule(schedRec.sys_id);
else
var sched = new Packages.com.glide.schedules.Schedule(schedRec.sys_id);
//Get the current date/time in correct format for duration calculation
var currentDateTime = current.requested_by_date.getGlideObject();
//Set the amount of time to add (in seconds)
var timeToAdd = 86400;
durToAdd = new GlideDuration(timeToAdd*1000);
var newDateTime = sched.add(currentDateTime, durToAdd, '');
//Set the 'requested_by_date' field to the new date/time
current.requested_by_date = newDateTime;
var schedRec = new GlideRecord('cmn_schedule');
schedRec.get('name', '8-5 weekdays');
if (typeof GlideSchedule != 'undefined')
var sched = new GlideSchedule(schedRec.sys_id);
else
var sched = new Packages.com.glide.schedules.Schedule(schedRec.sys_id);
//Get the current date/time in correct format for duration calculation
var currentDateTime = current.requested_by_date.getGlideObject();
//Set the amount of time to add (in seconds)
var timeToAdd = 86400;
durToAdd = new GlideDuration(timeToAdd*1000);
var newDateTime = sched.add(currentDateTime, durToAdd, '');
//Set the 'requested_by_date' field to the new date/time
current.requested_by_date = newDateTime;
Thanks for the post. I’ve always used Packages.com.glide… for schedules scripting, I was just wondering what we’re supposed to do considering the fact that this post claims that our ability to use it will be phased out?
http://community.service-now.com/blog/slightlyloony/classes-and-more-classes-oh-my
Cheers,
Alan.
Hey Alan,
I think that will happen eventually, but they’ve been saying that for over a year now. My advice is to continue using whatever you need to get the job done. Avoid ‘Packages’ calls wherever you can, but in this case they are completely necessary. As you do that, it’s probably a good idea to make a note of which calls you’ve used (and where you’ve used them) just in case you have to go back and change the code later. My guess is that dev will probably have to provide some automated way of switching to the non-packages calls in the future because EVERYONE uses these in one place or another.
Mark
Very true. I was hoping that there was another way just in case. Thanks for the reply.
FYI, ‘Packages’ calls will start to be phased out in the upcoming ‘Calgary’ release. I’ve updated the scripts above to be compatible no matter which version you’re on. ServiceNow will also be providing a migration utility.
I want to check if the difference between the effective date and today’s date is 1 day / 9 business hours. I am trying to use this as an example but not sure how to check date difference based on schedule? is sched.sub /subtract method is available to calculate the difference? Thanks.
For calculating the difference between dates using a schedule I think this post has a better example.
https://servicenowguru.wpengine.com/scripting/business-rules-scripting/calendar-based-incident-autoclose/
Note that you can (and should) just use
new GlideDateTime();
these days. For Schedule, we’ll make the appropriate parts of that API accessible, and documented, without needing Packages calls before we phase them out (see CapaJC’s note on the SlightlyLoony blog post.)
Thanks for the tip! I’ve replaced the ‘GlideDateTime’ packages call above with the new code.
Hi Mark,
In the Change Request App, do you know why the system would allow you to select a historical date(past date) in the End Date field when planning?
Example: Start Date is “today” Nov 17th 2011 and End Date is Nov 1st 2011.
How can I set the system to validate dates and not allow this to happen. Any ideas?
Thanks
Catherine
There’s no reason why it should other than the validation hasn’t been put in place. I’ve raised this issue to ServiceNow development but I don’t have a timeline for its addition to the product. It’s pretty easy to validate these types of things though. Here’s a link to some examples on the wiki.
http://wiki.service-now.com/index.php?title=Compare_Two_Date_Fields
Is there a way to subtract a day from a schedule? When i introduce a netgative number the script no longer works.
Hey Ryan,
I’m pretty sure there is, but I don’t know what it is off the top of my head. You might need to ask this one on the forums. If you find anything out, let me know and I’ll be sure to update this article.
Thanks.
I had this issue, this is what I can up with…
// Date Time variable taken from my form
var dateTime = g_form.getValue(‘u_date_and_time’);
// a duration number (minutes in this case)
var duration = g_form.getIntValue(‘u_duration’);
// Split up the Date and Time for manipulation and reordering
var dateSplit = dateTime.split(” “)[0];
var timeSplit = dateTime.split(” “)[1];
var date = dateSplit.split(“-“)[0];
var month = dateSplit.split(“-“)[1];
var year = dateSplit.split(“-“)[2];
var hours = parseInt(timeSplit.split(“:”)[0]);
var minutes = timeSplit.split(“:”)[1];
var seconds = timeSplit.split(“:”)[2];
// Reorder & combine dateTime and create the endDateTime
dateTime = (year + “-” + month + “-” + date + ” ” + hours + “:” + minutes + “:” + seconds);
// Where I added minutes on…
endDateTime = (year + “-” + month + “-” + date + ” ” + hours + “:” + minutes + duration + “:” + seconds);
// This allows you full flexibility with regards to changing any parts of the time or date and changing the order
In your case you could just do…
date = date – 1;
You may want to check that date isn’t 1 and if it is reduce the month by 1 and work out which month it is for the days then set the date to the last day of the previous month.
Not an ideal solution but it should help.
I found the error “Javascript compiler exception: Can’t find method com.glide.schedules.Schedule.add(string,string,string). ”
Error in line
var newDateTime = sched.add(currentDateTime, durToAdd, ”);
add() method can’t able to find in calgary release.
That’s probably because you’re instantiating ‘sched’ with a packages call…which no longer work in new Calgary instances. You’ll notice my code above works with both packages calls and the new code. Try replacing the ‘Packages’ line in your code with this.
var sched = new GlideSchedule(schedRec.sys_id);
I have already replaced my code with that still no output.
Here is my script –
Script include-
var AjaxHelperFunctions = Class.create();
AjaxHelperFunctions.prototype = Object.extendsObject(AbstractAjaxProcessor, {
datePastSLA: function() {
var firstDT = this.getParameter(‘sysparm_fdt’); //First Date-Time Field
var slaDays = this.getParameter(‘sysparm_sla_dt’);
var schedRec = new GlideRecord(‘cmn_schedule’);
schedRec.get(‘sys_id’, ‘090eecae0a0a0b260077e1dfa71da828’);
var sched = new GlideSchedule(schedRec.sys_id);
var timeToAdd = slaDays * 32400;
var durToAdd = new GlideDuration(timeToAdd*1000);
var newDateTime = sched.add(firstDT, durToAdd, ”);
var answer = ”;
answer = newDateTime;
return answer;
}
Client script
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
var stDt = g_form.getValue(‘u_start_date’);
var ajax = new GlideAjax(‘AjaxHelperFunctions’);
ajax.addParam(‘sysparm_name’, ‘datePastSLA’);
ajax.addParam(‘sysparm_fdt’, stDt);
ajax.addParam(‘sysparm_sla_dt’,’10’);
ajax.getXMLWait();
var answer = ajax.getAnswer();
g_form.setValue(‘u_end_date’,answer);
}
});
I’d be surprised if this worked in any release, let alone Calgary. The problem isn’t with the code I’ve supplied above, but you do have an issue with the date your passing from the client. The date is being passed as a string to your back-end function because that’s how the date values are formatted client-side. The ‘add’ method requires a ‘glideDateTime’ object, not a string. You’ll have to convert the string being passed into your function before using ‘sched.add’. Something like this should work better to replace the ‘var firstDT = this.getParameter(‘sysparm_fdt’); //First Date-Time Field’ line in your script above.
firstDT.setDisplayValue(this.getParameter(‘sysparm_fdt’));
Thanks Mark for your information.
It worked.
One question: Is there any way to check the method in a package because we faced issue because we didnt know what was the input parameter data type as well as output parameter.
Thanks in advance.
Unless ServiceNow has it documented somewhere (and I don’t think they do in this case) I don’t know how you would know unless you had used it before. A close examination of my code above would have told you the data type of the information being passed in but I can see how that might be overlooked. At least now you’ll know for next time. I would contact ServiceNow and request that they document GlideSchedule so it’s available in the future.
Thanks for all your help Mark
Dear Mark,
Thanks for this article which has already helped me on several occasions.
Do you know of any way to perform a substract instead of an add?
I tried with:
var timeToAdd = -86400; // negative time
durToAdd = new GlideDuration(timeToAdd*1000);
var newDateTime = sched.add(currentDateTime, durToAdd, ”);
But sched.add just returns the same value as currentDateTime.
Use case: I have a task where I know the due date, its duration, and a schedule, and would like to calculate the start date accordingly.
Thanks in advance for your reply,
David
I haven’t tried this specifically, but you might try ‘sched.subtract’ instead.
This unfortunately isn’t working – I have the same need as well. Not sure how to put in a negative duration (if that is even possible).
Hi Mark,
I tried following code in background script.
var todaysDate = new GlideDateTime();
todaysDate.setDisplayValue(gs.nowDateTime());
gs.print(“todaysDate display value : ” + todaysDate);
My Timezone is US/Eastern but, this is still returning output in GMT format asour instance is in GMT format.
Could you please let me know if i am missing anything?
Thanks & Regards,
Amisha Parekh
I always struggle with date time calculations and Mark is the guy who always helps me. Thanks Mark for all these posts!
Kind regards,
Sourabh