john_roberts
Mega Guru

I just came across a case where someone was comparing two date fields on the client to validate that the one was later than the other. To accomplish this they created a script include to compare dates on the server, then a client script was used to make an AJAX call to run the check in the script include.
The same check can be performed completely on the client saving the time it takes for a server round trip. Helper methods can be found in the calendar.js file on your client.

Here's a couple common uses:



/*
* onChange Client Script - change_request
* should be set to run on change of start_date and end_date
* Alert if planned end date is before planned start date
*/
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue == '') {
return;
}

var end = g_form.getValue("end_date");
var start = g_form.getValue("start_date");
// skip if start or end is blank
if (start == "" || end == "") {
return
}

// get user's date time display format
var format = g_user_date_time_format;
var isEndBeforeStart = compareDates(start, format, end, format);

// 1 (true) if start is greater than end
// 0 if end is greater than start of if they are the same
// -1 if either of the dates is in an invalid format

if (isEndBeforeStart) {
alert("End must be after start");
}
}


Caution with this next one since it may cause issues for users using a computer set to a different timezone than the user's ServiceNow account is using. The Date() object assumes the timezone of the browser.


/*
* onChange Client Script - change_request start_date field
* Alert if planned start date is before right now
*/
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue == '') {
return;
}

//get start date
var start = newValue;
//get Date object using user's display format
var dt = getDateFromFormat(start, g_user_date_time_format);
var rightNow = new Date();
if (dt < rightNow) {
alert("Start time is in the past, changing type to emergency.");
g_form.setValue("type", "Emergency");
}
}

Comments
ServiceNow Employee
ServiceNow Employee

Very cool!! I used glideAjax to do these date validations a lot. This is very helpful


Giga Sage

Thanks John. Something I've wanted to see for a very long time is a comprehensive document showing how you can do date/time/duration manipulations from both the server and the client. Adding, subtracting, and validating dates is so much more difficult than it should be.


Mega Expert

Just what the doctor ordered....

Could this be a sign of things to come out-of-the-cloud (box)?

Thus far this post on the wiki has been one of the most comprehensive sources on client-side date time:
http://community.service-now.com/forum/5423

But as Ivan said, it uses glideAjax.

Much prefer to accomplish this in the client.

Thank you John 🙂


ServiceNow Employee
ServiceNow Employee

Very nice. I had created the AJAX date/time calls because I was not aware of these functions. I actually had another situation where I had to do some date validation scripts today. So I thought I would try out these helper methods you mentioned. After digging into the calendar.js file I did wanted to point out some other cool things that may be helpful for others.

First the "compareDates(start, format, end, format)" function is awesome and very helpful.



var dt = getDateFromFormat(start, g_user_date_time_format);

The getDateFromFormat returns the date/time in milliseconds since Jan1, 1970 as in the .getTime() method. However I was unable to use other date methods such as getDay() etc because it does not return the date object. But this is easily remedied by putting the "dt" variable in a new Date() object like so. Then you have access to the full date object.


var dt = getDateFromFormat(start, g_user_date_time_format);
var newdt = newDate(dt);


I also noticed another function called "formatDate(date,format)". You can use this function to give it a date object and the format you want it outputted as. For example,


var dt = getDateFromFormat(start, g_user_date_time_format);
var newdt = newDate(dt);
var cabDateFormated = formatDate(newdt, "EE MMMM d, y hh:mm a ");

which will format the date to be "Tuesday February 28, 2012 03:00 PM ". Here is a little legend to explain more on the formatting codes

Field | Full Form | Short Form
-------------+--------------------+-----------------------
Year | yyyy (4 digits) | yy (2 digits), y (2 or 4 digits)
Month | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits)
| NNN (abbr.) |
Day of Month | dd (2 digits) | d (1 or 2 digits)
Day of Week | EE (name) | E (abbr)
Hour (1-12) | hh (2 digits) | h (1 or 2 digits)
Hour (0-23) | HH (2 digits) | H (1 or 2 digits)
Hour (0-11) | KK (2 digits) | K (1 or 2 digits)
Hour (1-24) | kk (2 digits) | k (1 or 2 digits)
Minute | mm (2 digits) | m (1 or 2 digits)
Second | ss (2 digits) | s (1 or 2 digits)
AM/PM | a |
Week in Yr. | ww (2 digits) | w ( 1 or 2 digits)
Day of Wk Num| D ( 1 digit) |
-------------+--------------------+-----------------------

And lastly, there is a function called "parseDate(val)" to parse out the date string and create a date object right off the bat. Now this appears to only work with Date fields not Date Time. So If you are using a date time field, like I was, you can just split it and take the first date part like I did below. This will take your field and return you a regular date object. You could then take your time and do a .setHours() on it. But creating the date object in my above example is probably easier.


var start = g_form.getValue("start_date");
var pd = parseDate(start.split(" ")[0]);


All in all I had to do one of those planned start cannot be before the next CAB meeting type validation scripts. With these helper methods you pointed out John and what I learned from the catalog.js file I was able to do it all client side.

Thank You.


Kilo Contributor

GMT config

Looks helpful John,

only one question:

what about the comparison when there is a local configuration of GMT different than the server one ?


Mega Guru

That's a good point, which is why I added the disclaimer.
"Caution with this next one since it may cause issues for users using a computer set to a different timezone than the user's ServiceNow account is using. The Date() object assumes the timezone of the browser."


Tera Contributor

Thank you so much, new to scripting and this really helped me 🙂


Giga Contributor

This is very helpful, thank you! How would I add 1 year to the present date in the second script? Is there a simple way of doing it without using glideAJAX and then the functions addYears etc.? Doing this in a client script.


Mega Guru

@ira_t you could try something like this.


[code]


var myDate = new Date();


var thisYear = myDate.getFullYear();


var nextYear = thisYear + 1;


myDate.setFullYear(nextYear);


[/code]


ServiceNow Employee
ServiceNow Employee

These methods for handling date calculations client side are very convenient but are not compatible with Service Portal as the necessary calendar.js file is not loaded.   Additionally, using an "onLoad" client script to define a set of utility functions to be utilized by other client scripts (onChange, onSubmit... ) will not work in Service Portal due to the way client scripts are loaded in Angular JS.... You can read more about this here... Using Onload for global/shared functions in catalog client scripts not working · Issue #185 · serv...    



If you are planning on using Service Portal as a means to access your Service Catalog you will have to avoid these technics


Mega Guru

Very helpful!

Giga Expert

This is the best article I've seen on the topic.  Old yes, but still very relevant.  Just wanted to provide an example of what I had to do on the Service Portal and from the platform Service Catalog to be able to compare just the date value from a date/time field to ensure the date selected was greater than the current date.  Both are catalog client scripts, the first for UI Type Mobile/Service Portal and the second for Desktop.  I'm sure there are more elaborate ways I could have done this and if so please share.  I wanted to provide the examples in case someone comes across the same requirement.

Mobile/Service Portal

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

g_form.hideFieldMsg('event_date_time');

//get value from date/time variable
var EventDateTime = moment(g_form.getValue('event_date_time')).format('YYYYMMDD');

//get current date/time
var NowDateTime = moment().format('YYYYMMDD');

if (NowDateTime >= EventDateTime)
{
g_form.hideFieldMsg('event_date_time');
g_form.showFieldMsg('event_date_time', 'The Date portion of Event Date/Time must be after the current date','error',true);
g_form.setValue('event_date_time','');
}

}

 

Desktop

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

var EventDateTime = newValue;
var dt = getDateFromFormat(EventDateTime, g_user_date_time_format);
var newdt = new Date(dt);
var EventDate = formatDate(newdt, 'yyyyMMdd');
var RightNow = new Date();
var RightNowDate = formatDate(RightNow, 'yyyyMMdd');

if (EventDate <= RightNowDate) {
g_form.clearValue('event_date_time');
g_form.showFieldMsg('event_date_time', 'The Date portion of Event Date/Time must be after the current date', 'error', true);

}
}

 

Take Care,

Jon