ServiceNow
Server-Side Utility APIs You Use Every Day: GlideDateTime, GlideElement, gs Methods
GlideDateTime — Date and time operations
ServiceNow stores dates in UTC internally. GlideDateTime handles timezone conversion, date math, and formatting.
// Current date/time
var now = new GlideDateTime();
gs.info(now.getValue()); // '2026-04-07 14:30:00' (UTC, internal)
gs.info(now.getDisplayValue()); // '2026-04-07 09:30:00' (user's timezone)
// Create from string
var dt = new GlideDateTime('2026-01-15 08:00:00');
// Date math — add/subtract
var dt = new GlideDateTime();
dt.addDaysUTC(7); // add 7 days
dt.addSeconds(3600); // add 1 hour
dt.addYearsUTC(1); // add 1 year
// Compare dates
var dt1 = new GlideDateTime('2026-01-01 00:00:00');
var dt2 = new GlideDateTime('2026-06-01 00:00:00');
gs.info(dt1.before(dt2)); // true
gs.info(dt1.after(dt2)); // false
// Difference between dates
var diff = GlideDateTime.subtract(dt1, dt2); // returns GlideDuration
gs.info(diff.getDayPart()); // number of days between
// Get parts
gs.info(now.getYearUTC()); // 2026
gs.info(now.getMonthUTC()); // 4
gs.info(now.getDayOfMonthUTC()); // 7
// gs date helpers — quick shortcuts
gs.info(gs.now()); // current date/time in user's format
gs.info(gs.nowDateTime()); // current date/time in system format
gs.info(gs.daysAgo(7)); // date/time 7 days ago
gs.info(gs.beginningOfLastMonth()); // first day of previous month
GlideElement — Field-level operations
When you access gr.field_name on a GlideRecord, you get a GlideElement object, not a raw value. These methods let you inspect and manipulate individual fields.
var gr = new GlideRecord('incident');
gr.get('number', 'INC0010001');
// Check if a field changed (only works in Business Rules with 'previous')
if (gr.priority.changes()) {
gs.info('Priority changed');
}
// Check if field changed TO a specific value
if (gr.state.changesTo(6)) {
gs.info('State changed to Resolved');
}
// Check if field changed FROM a specific value
if (gr.state.changesFrom(1)) {
gs.info('State was previously New');
}
// Check if a field is empty
if (gr.assigned_to.nil()) {
gs.info('No one assigned');
}
// gs.nil() works the same way
if (gs.nil(gr.getValue('assigned_to'))) {
gs.info('Also no one assigned');
}
// Get the field's label (not the column name)
gs.info(gr.priority.getLabel()); // 'Priority'
// Get choice list display value
gs.info(gr.priority.getDisplayValue()); // '1 - Critical'
// Reference field helpers
gs.info(gr.caller_id.getRefRecord().getValue('email')); // get the referenced record
gs (GlideSystem) — System utilities
Logging
gs.info('Informational message'); // System Logs > All
gs.warn('Warning message'); // shows as warning level
gs.error('Error message'); // shows as error level
gs.debug('Debug message'); // only shows when debug enabled
// Log with source context (appears in Source column)
gs.log('message', 'MyScriptInclude'); // legacy, use gs.info instead
User context
gs.info(gs.getUserID()); // sys_id of current user
gs.info(gs.getUserName()); // 'john.smith'
gs.info(gs.getUserDisplayName()); // 'John Smith'
gs.info(gs.getUser().getEmail()); // 'john@example.com'
// Check roles (server-side)
if (gs.hasRole('admin')) { }
if (gs.hasRole('itil')) { }
System properties
// Read a system property
var val = gs.getProperty('glide.servlet.uri'); // instance URL
var custom = gs.getProperty('x_myapp.feature_flag', 'default_value');
// Set a system property (use carefully)
gs.setProperty('x_myapp.last_sync', gs.nowDateTime());
Messages and events
// Show messages to the user (in Business Rules)
gs.addInfoMessage('Record saved successfully.');
gs.addErrorMessage('Cannot close without resolution notes.');
// Queue an event (for notifications, flows, or custom processing)
gs.eventQueue('incident.escalated', current, gs.getUserID(), current.getValue('assignment_group'));
// Prefer instantiating the Script Include (Class.create pattern).
// gs.include('MyUtilityLibrary') still exists for older includes, but
// new MyUtilityLibrary() is the usual modern call site.
var utils = new MyUtilityLibrary();
Data Policy vs UI Policy
Both control field mandatory/read-only behavior, but at different layers:
| Feature | UI Policy | Data Policy |
|---|---|---|
| Runs on | Client (browser) only | Server + Client |
| Enforced via API | No — only on the form | Yes — REST, import, scripts all respect it |
| Configuration | UI-only, no code | UI-only, no code |
| Use when | Form-only field behavior | Data integrity regardless of entry point |
If a field must always be mandatory — even for records created via API or Import Set — use a Data Policy. If it only matters when a user is filling out a form, UI Policy is sufficient.
Common traps
- GlideDateTime timezone confusion:
getValue()returns UTC,getDisplayValue()returns the user's timezone. When comparing dates in scripts, always usegetValue()or UTC methods. - gr.field.nil() vs gs.nil(): Both work, but
gs.nil()also handles null, undefined, and empty strings. Prefergs.nil(gr.getValue('field'))for defensive coding. - gs.getProperty() performance: System properties are cached, so repeated calls are fast. But do not call
gs.getProperty()inside a tight loop on a high-volume table — read it once and store it in a variable. - gs.addInfoMessage in async Business Rules: Will not display. The user's transaction is already complete. Only works in before/after BRs where the form is still in context.