© 2024 IQVIA - All Rights Reserved

Incomplete/Partial DateTime Future Check

Summary

This edit check compares the specified timing components of an Incomplete or Partial DateTime Item against the current date/time to ensure that the specified timing components are not in the future. This edit check is useful because the ‘Disallow Future Date’ Item setting only works for full DateTime Item datatypes.

Formal Expression

function getTimeZoneOffset(timeZoneId) { var timezoneOffsets = { "US/Pacific": -7 * 60 * 60 * 1000, "US/Mountain": -6 * 60 * 60 * 1000, "US/Central": -5 * 60 * 60 * 1000, "US/Eastern": -4 * 60 * 60 * 1000, "Europe/London": 0 * 60 * 60 * 1000, "Europe/Berlin": 1 * 60 * 60 * 1000, "Europe/Paris": 1 * 60 * 60 * 1000, "Europe/Madrid": 1 * 60 * 60 * 1000, "Europe/Rome": 1 * 60 * 60 * 1000, "Europe/Warsaw": 1 * 60 * 60 * 1000, "Europe/Moscow": 3 * 60 * 60 * 1000, "UTC": 0 * 60 * 60 * 1000, "GMT": 0 * 60 * 60 * 1000, }; return timezoneOffsets[timeZoneId] || 0; } function normalizeIncompleteDatetime(value, timeZoneId) { logger("Original value: " + value); // Split the date and time parts var parts = value.split('T'); var datePart = parts[0].split('-'); // Default year, month, and day var year = datePart[0] ? parseInt(datePart[0], 10) : 0; var month = datePart[1] && datePart[1].trim() !== '' ? parseInt(datePart[1], 10) - 1 : 0; // Default to January (month = 0) var day = datePart[2] && datePart[2].trim() !== '' ? parseInt(datePart[2], 10) : 1; // Default to 1st of the month // Split the time part and pad missing parts with defaults var timePart = parts.length > 1 ? parts[1].split(':') : []; var hour = timePart[0] && timePart[0].trim() !== '' ? parseInt(timePart[0], 10) : 0; var minute = timePart[1] && timePart[1].trim() !== '' ? parseInt(timePart[1], 10) : 0; var second = timePart.length > 2 && timePart[2].trim() !== '' ? parseInt(timePart[2], 10) : 0; // Create the Date object directly in the local timezone var normalizedDatetime = new Date(year, month, day, hour, minute, second); // Check if the date is valid if (isNaN(normalizedDatetime.getTime())) { logger("Error: Invalid Date created from input value."); customErrorMessage('The datetime "' + value + '" could not be interpreted as a valid date.'); return null; } // Adjust the datetime according to the timezone offset var timezoneOffset = getTimeZoneOffset(timeZoneId); normalizedDatetime = new Date(normalizedDatetime.getTime() - timezoneOffset); // Corrected: Subtracting the offset to convert from MT to UTC logger("Date object adjusted for " + timeZoneId + ": " + normalizedDatetime); return normalizedDatetime; } function isNotInFuture(datetimeValue, timeZoneId) { logger("Starting isNotInFuture check..."); // Normalize the incomplete datetime value directly in the timezone var normalizedDatetime = normalizeIncompleteDatetime(datetimeValue, timeZoneId); if (!normalizedDatetime) { // Return false if we couldn't create a valid date return false; } logger("Normalized datetime for comparison: " + normalizedDatetime); // Get the current time adjusted to the local timezone var now = new Date(); logger("Current local time: " + now); // Compare the datetime if (normalizedDatetime.getTime() >= now.getTime()) { var errorMessage = 'The datetime "' + datetimeValue + '" is in the future or exactly at the current time, which is not allowed.'; logger("Error: " + errorMessage); customErrorMessage(errorMessage); return false; } logger("Datetime is not in the future."); return true; } // Extract the timezone from formJson var timeZoneId = formJson.form.subject.volunteer.site.timeZoneId; logger("TimeZone ID: " + timeZoneId); // Run the check against the provided item value logger("Item value: " + itemJson.item.value); var isValid = isNotInFuture(itemJson.item.value, timeZoneId); logger("Validation result: " + isValid); return isValid;

Edit Check Walkthrough

https://www.loom.com/share/54c7967ffc9248ac89ea68249cdb3e84?sid=b91b751a-7c4b-4662-bd7e-0561e46943eb

Exported and Printed Copies Are Uncontrolled