ServiceNow Copying Date-Times In A Script

On a recent project, I needed to copy some date-time fields from one record to another.

I was using a server-based script include to do the copying, and assumed that I would be fine with a:

newRecord.created_at = oldRecord.getValue(‘created_at’) kind of construction.

What I found in practice though was that the date-time field on the copied record was 6 hours different than the field that had been copied from the original record.

This struck me as likely being due to a GMT vs local time kind of issue. That didn’t make a ton of sense given that we should just be copying one number from the back end to another field, also on the back end. Logically, I wasn’t expecting it to do any kind of changing of either of those two numbers to account for the user’s time setting, but apparently I was wrong.

Construction like this:

newRecord.created_at = oldRecord.getDisplayValue(‘created_at’)

Is returning a new record where the date-time field matches the original.

My best guess at this point is that ServiceNow runs some kind of middleware anytime you save a date-time (even on the back end) which takes whatever the user inputs and converts it to GMT.

In the original code, this meant that I was pulling GMT out of the database on the original record, and then that time was being shifted 6 hours before it was saved on the new record.

By getting the display value of the old record, we shifted the GMT time to local time, and then passed the local time to the middleware function which shifted it back to GMT before saving the new record to the database.

In short, any time you want to copy date-times, you need to use a .getDisplayValue() on the field you’re copying in order to have the value being saved in the new field match up with the old field.

ES6 Spread Operator

One of the frustrations of being a ServiceNow developer is the fact that you don’t get to use all of the latest Javascript bells and whistles because the Rhino engine simple doesn’t support them.

It would be less of an issue if I was happy to live completely inside of the ServiceNow ecosystem, but I have things that I want to build outside of ServiceNow, so I’m faced with having to mentally switch back and forth from ‘old’ JavaScript to ‘new’ JavaScript.

One of the things that I’m trying to remember to use more often outside of my ServiceNow projects is the ES6 Spread Operator. I recently had a use case where the spread operator was perfect:

I was building an express route that was creating a new record in the many side of a one-to-many relationship, and since I had authentication in place that confirmed that the user was who they said they were, I didn’t want to make the user pass in their user id so that I could tie the new entry to the user (the ‘one’ side of the one-to-many relationship).

— Without Spread Operator —
// Create a new item
router.post(‘/items’,auth,async(req,res)=>{
    const item=new Item({
        name: req.body.name,
       description: req.body.description,
       weight: req.body.weight,
        owner:req.user._id
    })
    try{
        await item.save();
        res.status(201).send(item);
    }catch(error) {
        res.status(400).send(error);
    }
})

— With Spread Operator —

// Create a new item
router.post(‘/items’,auth,async(req,res)=>{
    const item=new Item({
        …req.body,
        owner:req.user._id
    })
    try{
        await item.save();
        res.status(201).send(item);
    }catch(error) {
        res.status(400).send(error);
    }
})

 

Without the spread operator, I have to manually assign each of the request body items that I want to be placed into the object that is ultimately saved as a new record or document in the database.

With the spread operator, I can just tell the system to break the request body into its component parts and then place those parts into my new object.

Using the spread operator is obviously less typing than the alternative. That isn’t a massive deal when it comes to a request that only has 3 key-value pairs, but could become a big deal on a much larger request.

More importantly, though is the fact that using the spread operator future proofs your code much better than the alternative. If I were to go back and add something to my items table, and the corresponding requests coming into my route, the spread operator will just grab that new data seamlessly and start saving it to the database. I don’t have to remember to come back and modify that route to allow for the inclusion of that new data.

You could have a problem with the spread operator resulting in user input that you weren’t expecting being saved into your database, so you’ll want to do some testing if you’re using the spread operator on something that is user input.

In my case, I confirmed that Mongoose is trimming off anything that isn’t established as part of my model for the collection, which means that the spread operator was the perfect solution for this problem.

 

 

ServiceNow: Logging From Inside a GlideAjax

I recently had a piece of functionality that wasn’t coming together, and while I eventually figured out the issue, I would have gotten there much more quickly if I’d known for sure what method of logging to use inside of GlideAjax, or even if it was possible to log from inside a GlideAjax or not.

I tried searching online to confirm whether I should be using client or server logging, and didn’t find anything, so for future Dean, and anyone else who might by searching for this, the body of a GlideAjax runs on the server side of things, so logging inside of a GlideAjax uses gs.log().

More Madrid Bugs

I’ve continued to pursue the Madrid UI bug with ServiceNow that I referenced earlier, but while that has been going on I’ve found some other bugs, shortfalls, and other changes that took me by surprise in the system.

1. Under London, the ITIL user didn’t have any ability to edit the manager of a group from the sys_user_group table. Under Madrid that seems to have changed. Give that most organizations will be using that field to grant some level of access not enjoyed by the average user, there is a good chance that you’ll want to go in and lock that back down.

2. With Madrid, you now have the option to put a regex directly on the variables in your catalog items. We were really excited about this feature, but if you put a regex on a variable that is mandatory, and then test on the back end (rather than the service portal) the red * indicating that the field is mandatory stays red even after you’ve filled in the field. It works correctly on the service portal, which is where the end users will be going to actually request items, but I’ve had stuff kicked back to me from UAT because of this issue.

3. If you place a regex on a variable and then put an onChange client script in place to change that variable, you can run into problems. For example, I was asked to put a regex on a variable to enforce a string being entered in one of two formats. Setting the regex so that either format was acceptable worked just fine, but I also wanted to put a script in place to change strings entered in one format over to the other format so that we’d have consistently formatted data inside of the database. After parsing through the string, changing some of the characters, and then joining the array back up into a single string, the string no longer passed the regex. I ended up going with a different solution to fulfill the requirement, so it’s possible that there is something there that I was doing wrong without realizing it, but at first blush it looked like the string should have been passing the regex.