Custom Date Range Validation
Validate date fields against each other with custom business rules like working days, blackout periods, and lead times.
onChange Table: change_request Field: start_date
#onChange #date-validation #business-rules #blackout-dates #lead-time #change-management
Script Code
JavaScript
1function onChange(control, oldValue, newValue, isLoading, isTemplate) {
2 // Exit if form is loading
3 if (isLoading) {
4 return;
5 }
6
7 // Configuration
8 var minimumLeadTimeDays = 3; // Minimum days in advance
9 var minimumDurationHours = 1; // Minimum change window
10 var maximumDurationHours = 8; // Maximum change window
11
12 // Blackout periods (no changes allowed)
13 var blackoutPeriods = [
14 {start: '2024-12-24', end: '2024-12-26', reason: 'Holiday Freeze'},
15 {start: '2024-12-31', end: '2025-01-02', reason: 'New Year Freeze'}
16 ];
17
18 // Restricted days (require additional approval)
19 var restrictedDays = [0, 6]; // Sunday = 0, Saturday = 6
20
21 // Get both date fields
22 var startDate = g_form.getValue('start_date');
23 var endDate = g_form.getValue('end_date');
24
25 // Clear previous messages
26 g_form.hideFieldMsg('start_date');
27 g_form.hideFieldMsg('end_date');
28
29 if (!startDate) {
30 return;
31 }
32
33 var start = new Date(startDate);
34 var now = new Date();
35
36 // Validation 1: Check minimum lead time
37 var leadTimeMs = start - now;
38 var leadTimeDays = leadTimeMs / (1000 * 60 * 60 * 24);
39
40 if (leadTimeDays < minimumLeadTimeDays) {
41 var message = 'Start date must be at least ' + minimumLeadTimeDays +
42 ' days in advance. Current lead time: ' +
43 leadTimeDays.toFixed(1) + ' days.';
44 g_form.showFieldMsg('start_date', message, 'error');
45 g_form.addErrorMessage(message);
46 }
47
48 // Validation 2: Check if date is in the past
49 if (start < now) {
50 g_form.showFieldMsg('start_date', 'Start date cannot be in the past', 'error');
51 }
52
53 // Validation 3: Check blackout periods
54 for (var i = 0; i < blackoutPeriods.length; i++) {
55 var blackout = blackoutPeriods[i];
56 var blackoutStart = new Date(blackout.start);
57 var blackoutEnd = new Date(blackout.end);
58
59 if (start >= blackoutStart && start <= blackoutEnd) {
60 var message = 'Change cannot be scheduled during ' + blackout.reason +
61 ' (' + blackout.start + ' to ' + blackout.end + ')';
62 g_form.showFieldMsg('start_date', message, 'error');
63 g_form.addErrorMessage(message);
64 }
65 }
66
67 // Validation 4: Check restricted days (weekends)
68 var dayOfWeek = start.getDay();
69 if (restrictedDays.indexOf(dayOfWeek) !== -1) {
70 var dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
71 'Thursday', 'Friday', 'Saturday'];
72 var message = 'Changes scheduled on ' + dayNames[dayOfWeek] +
73 ' require additional approval';
74 g_form.showFieldMsg('start_date', message, 'warning');
75 g_form.addInfoMessage(message);
76
77 // Set flag for additional approval requirement
78 g_form.setValue('u_requires_additional_approval', 'true');
79 }
80
81 // Validation 5: Check business hours (e.g., 9 AM - 5 PM)
82 var hour = start.getHours();
83 var isBusinessHours = (hour >= 9 && hour < 17);
84
85 if (!isBusinessHours) {
86 g_form.showFieldMsg('start_date',
87 'After-hours change: Additional approval may be required',
88 'warning');
89 }
90
91 // Validation 6: Validate against end date if present
92 if (endDate) {
93 var end = new Date(endDate);
94
95 // End must be after start
96 if (end <= start) {
97 g_form.showFieldMsg('end_date', 'End date must be after start date', 'error');
98 } else {
99 // Check duration
100 var durationMs = end - start;
101 var durationHours = durationMs / (1000 * 60 * 60);
102
103 if (durationHours < minimumDurationHours) {
104 var message = 'Change window must be at least ' +
105 minimumDurationHours + ' hour(s)';
106 g_form.showFieldMsg('end_date', message, 'error');
107 }
108
109 if (durationHours > maximumDurationHours) {
110 var message = 'Change window exceeds maximum of ' +
111 maximumDurationHours + ' hours. ' +
112 'Consider breaking into multiple changes.';
113 g_form.showFieldMsg('end_date', message, 'warning');
114 }
115
116 // Show duration info
117 var durationInfo = 'Change window: ' + durationHours.toFixed(1) + ' hours';
118 g_form.showFieldMsg('end_date', durationInfo, 'info');
119 }
120 }
121
122 // Validation 7: Check for conflicts with other changes
123 // This would require GlideAjax call to check server-side
124 // Simplified example:
125 /*
126 var ga = new GlideAjax('ChangeConflictChecker');
127 ga.addParam('sysparm_name', 'checkConflicts');
128 ga.addParam('sysparm_start_date', startDate);
129 ga.addParam('sysparm_end_date', endDate);
130 ga.addParam('sysparm_ci', g_form.getValue('cmdb_ci'));
131
132 ga.getXMLAnswer(function(response) {
133 if (response === 'true') {
134 g_form.showFieldMsg('start_date',
135 'Warning: Another change is scheduled during this time',
136 'warning');
137 }
138 });
139 */
140}
How to Use
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
Related Scripts
Auto-populate Related Fields
Automatically populate fields when a reference field changes (e.g., populate caller's phone and email when caller is selected).
Conditional Mandatory Fields
Make fields mandatory based on the value of another field (e.g., require close notes only when state is Resolved).
Dynamic Field Visibility
Show or hide fields based on another field's value (e.g., show "Other reason" field only when user selects "Other" from dropdown).