← Script library

Client Scripts

Custom Date Range Validation

Validate date fields against each other with custom business rules like working days, blackout periods, and lead times.

JavaScript
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
  // Exit if form is loading
  if (isLoading) {
    return;
  }

  // Configuration
  var minimumLeadTimeDays = 3;  // Minimum days in advance
  var minimumDurationHours = 1;  // Minimum change window
  var maximumDurationHours = 8;  // Maximum change window

  // Blackout periods (no changes allowed)
  var blackoutPeriods = [
    {start: '2024-12-24', end: '2024-12-26', reason: 'Holiday Freeze'},
    {start: '2024-12-31', end: '2025-01-02', reason: 'New Year Freeze'}
  ];

  // Restricted days (require additional approval)
  var restrictedDays = [0, 6];  // Sunday = 0, Saturday = 6

  // Get both date fields
  var startDate = g_form.getValue('start_date');
  var endDate = g_form.getValue('end_date');

  // Clear previous messages
  g_form.hideFieldMsg('start_date');
  g_form.hideFieldMsg('end_date');

  if (!startDate) {
    return;
  }

  var start = new Date(startDate);
  var now = new Date();

  // Validation 1: Check minimum lead time
  var leadTimeMs = start - now;
  var leadTimeDays = leadTimeMs / (1000 * 60 * 60 * 24);

  if (leadTimeDays < minimumLeadTimeDays) {
    var message = 'Start date must be at least ' + minimumLeadTimeDays + 
                  ' days in advance. Current lead time: ' + 
                  leadTimeDays.toFixed(1) + ' days.';
    g_form.showFieldMsg('start_date', message, 'error');
    g_form.addErrorMessage(message);
  }

  // Validation 2: Check if date is in the past
  if (start < now) {
    g_form.showFieldMsg('start_date', 'Start date cannot be in the past', 'error');
  }

  // Validation 3: Check blackout periods
  for (var i = 0; i < blackoutPeriods.length; i++) {
    var blackout = blackoutPeriods[i];
    var blackoutStart = new Date(blackout.start);
    var blackoutEnd = new Date(blackout.end);

    if (start >= blackoutStart && start <= blackoutEnd) {
      var message = 'Change cannot be scheduled during ' + blackout.reason + 
                   ' (' + blackout.start + ' to ' + blackout.end + ')';
      g_form.showFieldMsg('start_date', message, 'error');
      g_form.addErrorMessage(message);
    }
  }

  // Validation 4: Check restricted days (weekends)
  var dayOfWeek = start.getDay();
  if (restrictedDays.indexOf(dayOfWeek) !== -1) {
    var dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 
                    'Thursday', 'Friday', 'Saturday'];
    var message = 'Changes scheduled on ' + dayNames[dayOfWeek] + 
                 ' require additional approval';
    g_form.showFieldMsg('start_date', message, 'warning');
    g_form.addInfoMessage(message);
    
    // Set flag for additional approval requirement
    g_form.setValue('u_requires_additional_approval', 'true');
  }

  // Validation 5: Check business hours (e.g., 9 AM - 5 PM)
  var hour = start.getHours();
  var isBusinessHours = (hour >= 9 && hour < 17);
  
  if (!isBusinessHours) {
    g_form.showFieldMsg('start_date', 
                       'After-hours change: Additional approval may be required', 
                       'warning');
  }

  // Validation 6: Validate against end date if present
  if (endDate) {
    var end = new Date(endDate);

    // End must be after start
    if (end <= start) {
      g_form.showFieldMsg('end_date', 'End date must be after start date', 'error');
    } else {
      // Check duration
      var durationMs = end - start;
      var durationHours = durationMs / (1000 * 60 * 60);

      if (durationHours < minimumDurationHours) {
        var message = 'Change window must be at least ' + 
                     minimumDurationHours + ' hour(s)';
        g_form.showFieldMsg('end_date', message, 'error');
      }

      if (durationHours > maximumDurationHours) {
        var message = 'Change window exceeds maximum of ' + 
                     maximumDurationHours + ' hours. ' +
                     'Consider breaking into multiple changes.';
        g_form.showFieldMsg('end_date', message, 'warning');
      }

      // Show duration info
      var durationInfo = 'Change window: ' + durationHours.toFixed(1) + ' hours';
      g_form.showFieldMsg('end_date', durationInfo, 'info');
    }
  }

  // Validation 7: Check for conflicts with other changes
  // This would require GlideAjax call to check server-side
  // Simplified example:
  /*
  var ga = new GlideAjax('ChangeConflictChecker');
  ga.addParam('sysparm_name', 'checkConflicts');
  ga.addParam('sysparm_start_date', startDate);
  ga.addParam('sysparm_end_date', endDate);
  ga.addParam('sysparm_ci', g_form.getValue('cmdb_ci'));
  
  ga.getXMLAnswer(function(response) {
    if (response === 'true') {
      g_form.showFieldMsg('start_date', 
                         'Warning: Another change is scheduled during this time', 
                         'warning');
    }
  });
  */
}

How to use it

1. Create onChange Client Scripts for both start_date and end_date fields 2. Customize minimumLeadTimeDays and duration limits for your policies 3. Update blackoutPeriods array with your freeze dates 4. Adjust restrictedDays for your organization (weekends, specific days) 5. Create duplicate script for end_date field 6. Consider adding GlideAjax call for conflict checking 7. Test all date scenarios including edge cases 8. Document validation rules for users

Adapt the table names, fields, and conditions to your instance. Test the behavior in a development environment before using it in production.