Catalog variable Date/Time validation – 2 working days (Sun–Thu) with hour‑based lead time

Sirri
Tera Guru

Hi Community,

I’m working on a Service Catalog Date/Time variable validation and would like confirmation or suggestions for improvement.

Variable Details

  • Variable name: time_to_send_out_comms
  • Variable type: Date/Time
  • Used on: Service Request (SR)

    Business Requirement

    1. Past Date/Time Validation

    • The selected date/time must not be in the past

    If user selects a past date/time, show the error message:

    “The time chosen to send out the communication occurs in the past, kindly select a future date/time to proceed.”

    2. Minimum Lead Time – 2 Working Days (Hour‑Based)

    • The selected date/time must be at least 2 working days after the current date/time
    • Working days: Sunday to Thursday
      (Friday and Saturday are non‑working days)
    • Lead time must be hour‑based, not just date‑based

    Example

    Current date/time:

    13/May/2026 13:05:00 (Wednesday)

    Valid selections

    • 17/May/2026 13:06:00
    • 17/May/2026 15:00:00
    • Any date/time after the same HH:mm:ss on the 2nd working day

    Invalid selections

    • 17/May/2026 13:04:00
    • Any date/time before 17/May/2026 13:05:00

    If user does not allow 2 working days lead time, show the error message:

    “Please allow two working days lead time for approvals and content review.”
    Please provide with exact code so it will helpful to me.

    Thank you

     





1 ACCEPTED SOLUTION

Hello @Sirri 

Here is the updated onChange Client script:

function onChange(control, oldValue, newValue, isLoading) {
    //Stop processing further code from running when the form initially loads with pre-existing values
    if (isLoading) {
        return;
    }
    // Stop processing further code from running when user clears the field, as there is nothing to validate
    if (!newValue || newValue == '') {
        return;
    }

    var pastMsg = "The time chosen to send out the communication occurs in the past, kindly select a future date/time to proceed.";
    var leadMsg = "Please allow two working days lead time for approvals and content review.";
    var weekendMsg = "Communications cannot be scheduled on a Friday or Saturday as these are non-working days. Please select a working day (Sunday–Thursday).";

    // Month abbreviation to 0-indexed number mapping for display-style format (e.g., "11/May/2026 10:41:26")
    var monthMap = {
        'Jan': 0, 'Feb': 1, 'Mar': 2, 'Apr': 3,
        'May': 4, 'Jun': 5, 'Jul': 6, 'Aug': 7,
        'Sep': 8, 'Oct': 9, 'Nov': 10, 'Dec': 11
    };

    // Required to separate the date component from the time component for independent parsing
    var dateParts = newValue.split(' ');

    // Required to extract hour, minute, and second as separate values from the time string like "12:48:24"
    var timeParts = dateParts[1].split(':');

    var year, month, day;

    //Please go through below links to understand below code:

    /*

    indexOf(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf
    split(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split
    parseInt(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
    Date(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date

    */

    // For Date Time format: "11/May/2026 10:41:26"
    if (dateParts[0].indexOf('/') !== -1) { // check whether date contain a forward slash
        // Display-style format: "11/May/2026"
        var dateComponents = dateParts[0].split('/'); // Splits "11/May/2026" into pieces: ["11", "May", "2026"]
        day = parseInt(dateComponents[0], 10); // First piece "11" which is day = 11
        month = monthMap[dateComponents[1]]; // Second piece "May" → look up in monthMap → month = 4 (0-indexed)
        year = parseInt(dateComponents[2], 10); // Third piece "2026" → year = 2026
    
	} else {
        //For Date Time format:  "2026-05-20" -- You can comment this if you don't need it.
        var dateComponents = dateParts[0].split('-');
        year = parseInt(dateComponents[0], 10);
        month = parseInt(dateComponents[1], 10) - 1;
        day = parseInt(dateComponents[2], 10);
    }

    // Required to construct a valid JavaScript Date; month is 0-indexed (0=Jan, 11=Dec)
    var selectedDate = new Date(year, month, day, parseInt(timeParts[0], 10), parseInt(timeParts[1], 10), parseInt(timeParts[2], 10));

    // Capture the current date/time as the baseline for both past-date and lead-time validations
    var now = new Date();

    // VALIDATION #1: Communications cannot be scheduled in the past
    if (selectedDate.getTime() < now.getTime()) {
        alert(pastMsg);
        g_form.setValue('time_to_send_out_comms', ''); //Clear the variable value
        return; // Stop processing further code
    }

    // VALIDATION #2: Communications cannot be scheduled on non-working days (Friday or Saturday)
    // getDay() returns 0=Sunday, 1=Monday, 2=Tuesday, 3=Wednesday, 4=Thursday, 5=Friday, 6=Saturday
    var selectedDayOfWeek = selectedDate.getDay();
    if (selectedDayOfWeek === 5 || selectedDayOfWeek === 6) {
        alert(weekendMsg);
        g_form.setValue('time_to_send_out_comms', ''); //Clear the variable value
        return; // Stop processing further code
    }

    // VALIDATION #3: Calculate the earliest allowed date/time by starting from the current moment and adding 2 working days while preserving the exact time (hour-based comparison)
    var minDate = new Date(now.getTime());

    // Track how many valid working days have been counted toward the 2-day minimum
    var workingDaysAdded = 0;

    // Iterate day-by-day until exactly 2 working days (Sunday–Thursday) have been accumulated
    while (workingDaysAdded < 2) {
        // Advance the date by one calendar day for each iteration
        minDate.setDate(minDate.getDate() + 1);
        // Determine if the current day in the loop is a working day or a non-working day
        var dayOfWeek = minDate.getDay();
        // Skip Friday (5) and Saturday (6) as they are defined as non-working days per business requirements
        if (dayOfWeek !== 5 && dayOfWeek !== 6) {
            // Count only valid working days toward the 2-day lead time requirement
            workingDaysAdded++;
        }
    }

    // Selected date/time must be at or after the same hour/minute/second on the 2nd working day from now
    if (selectedDate.getTime() < minDate.getTime()) {
        alert(leadMsg);
        g_form.setValue('time_to_send_out_comms', ''); //Clear the variable value
        return; // Stop processing further code
    }
}

VishalJaswal_0-1778855253994.png



Validation Results:

VishalJaswal_1-1778855289743.png

VishalJaswal_2-1778855302986.png

 

VishalJaswal_3-1778855313382.pngVishalJaswal_4-1778855323279.png

VishalJaswal_5-1778855335437.png

 




Hope that helps!

View solution in original post

27 REPLIES 27

Tejas Adhalrao
Kilo Sage

Hi @Sirri  , here is update script with screenshorts 

on change client script  (reoplace your variable name)

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

    // Hide any previous error messages on this field
    g_form.hideFieldMsg('select_date_time', true);

    // 1. Get Selected Date (Convert ServiceNow format to JS Date)
    var selectedDateStr = g_form.getValue('select_date_time');
    var selectedDate = new Date(getDateFromFormat(selectedDateStr, g_user_date_time_format));
    var now = new Date();

    // ----------------------------------------------------------------
    // 2. Past Date/Time Validation
    // ----------------------------------------------------------------
    if (selectedDate <= now) {
        g_form.addErrorMessage('The time chosen occurs in the past. Please select a future date/time.' );
        g_form.clearValue('select_date_time');
        return;
    }

    // ----------------------------------------------------------------
    // 3. Minimum 2 Working Days (Sun-Thu) Lead Time Validation
    // ----------------------------------------------------------------
    var minAllowedDate = new Date(now.getTime());
    var workingDaysAdded = 0;

    // Loop until we have added 2 working days
    while (workingDaysAdded < 2) {
        minAllowedDate.setDate(minAllowedDate.getDate() + 1);
        
        var dayOfWeek = minAllowedDate.getDay(); 
        // JS Date getDay(): 0=Sun, 1=Mon, 2=Tue, 3=Wed, 4=Thu, 5=Fri, 6=Sat
        
        // Working days: Sunday(0) through Thursday(4)
        if (dayOfWeek >= 0 && dayOfWeek <= 4) {
            workingDaysAdded++;
        }
    }

    // Final Comparison
    if (selectedDate < minAllowedDate) {
        g_form.addErrorMessage('Please allow at least two working days (Sun-Thu) lead time for approvals.');
        g_form.clearValue('select_date_time');
    }
}

 Test Case :

 today date  - 15/5/2026

 

1) if you select the past date 14/5/2026 shows error

TejasAdhalrao_0-1778843915696.png

 

2) if you select the non working days (16/5/2026 less 2 working days)

TejasAdhalrao_1-1778844034295.png

 

3)if Less than 2 working days ( 18/5/2026)

TejasAdhalrao_2-1778844122308.png

 

 

 

If this response was helpful, please consider marking it as Correct and Helpful. You may mark more than one reply as an accepted solution.

thanks ,

tejas 😊

 

 

 

@Tejas Adhalrao ,

Thank you for your response.

I have tested the provided code, and it is working correctly in some scenarios. However, when I test with 22nd and 23rd May, the expected behavior is not achieved on my end.

Could you please revalidate this scenario at your end and confirm? It would be helpful if you could review and provide an updated solution that fully meets the requirement.

Thank you

pr8172510
Tera Guru

Hey @Sirri,

 

OnChange Client Script

Name: Validate Communication Date
Variable: time_to_send_out_comms
Type: onChange


function onChange(control, oldValue, newValue, isLoading) {

// Don't run while form is loading or field is empty
if (isLoading || !newValue || newValue == '') {
return;
}

// Clear any existing error messages
g_form.hideFieldMsg('time_to_send_out_comms', true);

// Parse the selected date (format: "15/May/2026 13:05:00")
var selected = parseCustomDate(newValue);
var now = new Date();

// --------------------------------------------
// 1. Past Date Validation (including time)
// --------------------------------------------
if (selected < now) {
g_form.showFieldMsg(
'time_to_send_out_comms',
'The time chosen to send out the communication occurs in the past, kindly select a future date/time to proceed.',
'error'
);
g_form.clearValue('time_to_send_out_comms');
return;
}

// --------------------------------------------
// 2. Calculate Minimum Allowed Date (2 working days from now)
// Working days: Sunday to Thursday (Friday & Saturday excluded)
// Preserves the exact time (hour/minute/second)
// --------------------------------------------
var minDate = new Date(now.getTime());
var workingDaysAdded = 0;
var maxIterations = 30; // Safety break

while (workingDaysAdded < 2 && maxIterations-- > 0) {
// Add 1 day
minDate.setDate(minDate.getDate() + 1);

// Get day of week (0 = Sunday, 1 = Monday, ... 6 = Saturday)
var dayOfWeek = minDate.getDay();

// Working days: Sunday(0), Monday(1), Tuesday(2), Wednesday(3), Thursday(4)
// Non-working days: Friday(5), Saturday(6)
if (dayOfWeek !== 5 && dayOfWeek !== 6) {
workingDaysAdded++;
}
}

// Compare selected date with minimum allowed date
if (selected < minDate) {
g_form.showFieldMsg(
'time_to_send_out_comms',
'Please allow two working days lead time for approvals and content review.',
'error'
);
g_form.clearValue('time_to_send_out_comms');
return;
}

// --------------------------------------------
// 3. Helper function to parse "DD/MMM/YYYY HH:MM:SS" format
// --------------------------------------------
function parseCustomDate(dateStr) {
var parts = dateStr.split(' ');
var datePart = parts[0];
var timePart = parts[1];

// Parse date: "15/May/2026"
var dateComponents = datePart.split('/');
var day = parseInt(dateComponents[0], 10);
var monthStr = dateComponents[1];
var year = parseInt(dateComponents[2], 10);

// Month mapping (Jan = 0, Feb = 1, etc.)
var monthMap = {
'Jan': 0, 'Feb': 1, 'Mar': 2, 'Apr': 3,
'May': 4, 'Jun': 5, 'Jul': 6, 'Aug': 7,
'Sep': 8, 'Oct': 9, 'Nov': 10, 'Dec': 11
};
var month = monthMap[monthStr];

// Parse time: "13:05:00"
var timeComponents = timePart.split(':');
var hour = parseInt(timeComponents[0], 10);
var minute = parseInt(timeComponents[1], 10);
var second = parseInt(timeComponents[2], 10);

return new Date(year, month, day, hour, minute, second);
}
}

@pr8172510 

Thank you for your response.

Could you please verify the functionality specifically for 22nd and 23rd May? It is not working as expected on my end.

Kindly review this scenario and provide the updated code aligned with the requirement.

Thank you.

function onChange(control, oldValue, newValue, isLoading) {

// Don't run while form is loading or field is empty
if (isLoading || !newValue || newValue == '') {
return;
}

// Clear any existing error messages
g_form.hideFieldMsg('time_to_send_out_comms', true);

// Parse the selected date (format: "DD/MMM/YYYY HH:MM:SS")
var selected = parseCustomDate(newValue);
var now = new Date();

// --------------------------------------------
// 1. Past Date Validation (including time)
// --------------------------------------------
if (selected < now) {
g_form.showFieldMsg(
'time_to_send_out_comms',
'The time chosen to send out the communication occurs in the past, kindly select a future date/time to proceed.',
'error'
);
g_form.clearValue('time_to_send_out_comms');
return;
}

// --------------------------------------------
// 2. Block Friday (5) and Saturday (6) selections
// --------------------------------------------
var selectedDayOfWeek = selected.getDay(); // 0=Sun, 1=Mon, 2=Tue, 3=Wed, 4=Thu, 5=Fri, 6=Sat

if (selectedDayOfWeek === 5 || selectedDayOfWeek === 6) {
g_form.showFieldMsg(
'time_to_send_out_comms',
'Communications cannot be scheduled on a Friday or Saturday as these are non-working days. Please select a working day (Sunday–Thursday).',
'error'
);
g_form.clearValue('time_to_send_out_comms');
return;
}

// --------------------------------------------
// 3. Calculate Minimum Allowed Date (2 working days from now)
// Working days: Sunday to Thursday (Friday & Saturday excluded)
// Preserves the exact time (hour/minute/second)
// --------------------------------------------
var minDate = new Date(now.getTime());
var workingDaysAdded = 0;
var maxIterations = 30; // Safety break

while (workingDaysAdded < 2 && maxIterations-- > 0) {
// Add 1 day
minDate.setDate(minDate.getDate() + 1);

// Get day of week (0 = Sunday, 1 = Monday, ... 6 = Saturday)
var dayOfWeek = minDate.getDay();

// Working days: Sunday(0), Monday(1), Tuesday(2), Wednesday(3), Thursday(4)
// Non-working days: Friday(5), Saturday(6)
if (dayOfWeek !== 5 && dayOfWeek !== 6) {
workingDaysAdded++;
}
}

// Compare selected date with minimum allowed date (hour-based)
if (selected < minDate) {
g_form.showFieldMsg(
'time_to_send_out_comms',
'Please allow two working days lead time for approvals and content review.',
'error'
);
g_form.clearValue('time_to_send_out_comms');
return;
}

// --------------------------------------------
// 4. Helper function to parse "DD/MMM/YYYY HH:MM:SS" format
// --------------------------------------------
function parseCustomDate(dateStr) {
var parts = dateStr.split(' ');
var datePart = parts[0];
var timePart = parts[1];

// Parse date: "15/May/2026"
var dateComponents = datePart.split('/');
var day = parseInt(dateComponents[0], 10);
var monthStr = dateComponents[1];
var year = parseInt(dateComponents[2], 10);

// Month mapping (Jan = 0, Feb = 1, etc.)
var monthMap = {
'Jan': 0, 'Feb': 1, 'Mar': 2, 'Apr': 3,
'May': 4, 'Jun': 5, 'Jul': 6, 'Aug': 7,
'Sep': 8, 'Oct': 9, 'Nov': 10, 'Dec': 11
};
var month = monthMap[monthStr];

// Parse time: "13:05:00"
var timeComponents = timePart.split(':');
var hour = parseInt(timeComponents[0], 10);
var minute = parseInt(timeComponents[1], 10);
var second = parseInt(timeComponents[2], 10);

return new Date(year, month, day, hour, minute, second);
}
}