I recently encountered a problem while setting a fixed time for future events in a script. The issue arose when dealing with daylight saving time (DST) – the time was incorrectly skewed by one hour. The user interface (UI) functions as expected, allowing you to set a time in the future and correctly assigning the time zone (TZ) and DST offset to the value, which is then saved as a UTC DateTime value. However, when using the GlideSchedule function to retrieve a range of dates, the time zone is taken into account but the DST offset is not.

I attempted to solve the problem by migrating all the time zones to the “Country/City” format, as there is a knowledge base (KB) article from ServiceNow (SN) that states DST is not accounted for in the old time zones. However, I later found another KB article that indicates they are linked. Changing the time zone did not resolve the issue, and I eventually determined that the problem was on the script side – even though a time zone with DST is provided, the system does not automatically add the offset to the values.

I hope this information is helpful to others who may encounter a similar problem in the future. It is important to carefully consider time zones and DST offsets when working with dates and times in scripts to ensure accurate results.

Competing KB’s:

https://support.servicenow.com/kb?id=kb_article_view&sysparm_article=KB0594661

https://support.servicenow.com/kb?id=kb_article_view&sysparm_article=KB0960564

Excerpt from my large Script Include, this is what takes the GlideDateTime object in and spits a DST-corrected GlideDtateTime object out:

    setDstOffset: function(time) {

        // Make sure we account for DST
        var dstOffset = (-Number(time.getDSTOffset() / 1000));
        time.addSeconds(dstOffset);
        return time;

Where I’m creating the timespan and calling the DST function:

   refreshTasksInSchedule: function(spansStart, spansEnd, schedule, template, newTask_ID) {
        if (!spansStart || !spansEnd)
            return;
        var timeMap = schedule.getTimeMap(spansStart, spansEnd);
        timeMap.buildMap(schedule.getTimeZone());

        // Skip the first element in the timeMap if it spans now 
        if (schedule.isInSchedule(new GlideDateTime()) && timeMap.hasNext() && !newTask_ID) {
            timeMap.next();
        }

        var timeSpan;
        while (timeMap.hasNext()) {
            count += 1;
            timeSpan = timeMap.next();

            var start = timeSpan.getStart().getGlideDateTime();
            var end = timeSpan.getEnd().getGlideDateTime();

			var today = new GlideDateTime(gs.endOfToday());
			if (start >= today){
				var newTaskID = this.refreshTask(template, start, end, newTask_ID);
				...
			}
        }

    },
    refreshTask: function(template, start, end, newTask_ID) {
        var timeZone = Packages.java.util.TimeZone.getTimeZone(template.u_time_zone);

        var startDate = new GlideDateTime(start);
        startDate.addSeconds(this.getTzOffsetSeconds(timeZone));

        // Setting DST offset for time
        startDate = this.setDstOffset(startDate);

        var endDate = new GlideDateTime(end);
        endDate.addSeconds(this.getTzOffsetSeconds(timeZone));

        // Setting DST offset for time
        endDate = this.setDstOffset(endDate);
        ...
}