Scripted REST ‐ Validating Date Formats - ben-vargas/servicenow-wiki GitHub Wiki

This article explains how to validate date and date/time values within a ServiceNow Scripted REST API, ensuring that the provided input matches the expected format based on the user's locale settings. This is crucial for handling data correctly when receiving data from external systems.

The Challenge

When building Scripted REST APIs, you often receive date and date/time values from external systems. These systems might use different date formats than your ServiceNow instance. To ensure data consistency, you need to validate that incoming date values adhere to the correct format based on the user's locale settings before processing the request.

The Solution

The solution involves using Java's SimpleDateFormat class to parse incoming date strings and validate that they match the expected format using gs.getDateTimeFormat(). This allows for dynamic date validation based on the user settings.

Code Snippets:

Here's the code snippet for validating a date/time string:

function validateDateFormat(dateChk) {
    try {
        var simplified_date = new Packages.java.text.SimpleDateFormat();
        simplified_date.setLenient(false);
        simplified_date.applyPattern(gs.getDateTimeFormat());
        simplified_date.parse(dateChk);
        return true;
    } catch (err) {
        return false;
    }
}

Explanation:

  1. function validateDateFormat(dateChk):

    • This function takes a date string (dateChk) as input and returns true if the format is valid, false otherwise.
  2. var simplified_date = new Packages.java.text.SimpleDateFormat();:

    • Creates an instance of Java's SimpleDateFormat class to handle date parsing and formatting.
  3. simplified_date.setLenient(false);:

    • Sets the SimpleDateFormat to be non-lenient, meaning it will strictly adhere to the provided format. This prevents it from accepting dates that are not valid or might be a different format.
  4. simplified_date.applyPattern(gs.getDateTimeFormat());:

    • Applies the date/time format pattern from ServiceNow using gs.getDateTimeFormat(), which is a user specific value.
  5. simplified_date.parse(dateChk);:

    • Attempts to parse the input date string (dateChk) using the set pattern. If parsing is successful, it means the format is valid.
  6. try { ... } catch (err) { ... }:

    • The try...catch block handles the parse() method exceptions, as they occur when the input string cannot be parsed.
    • If parsing fails, the function returns false. If it is successful, it returns true.

Example Usage within a Scripted REST API:

Here’s an example of how to use this function within a Scripted REST API resource, specifically when processing input of a glide_date_time field:

// Assuming body is a JSON object with the input
// And FIELDS is an object defining the schema of what is being input.
else if (FIELDS[key].type == 'glide_date_time') {
    try {
        var simplified_date = new Packages.java.text.SimpleDateFormat();
        simplified_date.setLenient(false);
        simplified_date.applyPattern(gs.getDateTimeFormat());
        var mydate = simplified_date.parse(body[key]);
        changeGR[key] = body[key];
    }
    catch (err) {
        var bad_field = {};
        bad_field.field = key;
        bad_field.info = 'Date not in valid format: ' + body[key] + ' -- Expecting: ' + gs.getDateTimeFormat();
        invalid_fields.push(bad_field);
    }
}

Explanation:

  1. else if (FIELDS[key].type == 'glide_date_time') { ... }
  • This logic checks the type of the field that is being processed by the API.
  1. try { ... } catch (err) { ... }:
    • The try...catch block handles the parsing.
    • If parsing is successful, then the body[key] value is assigned to the GlideRecord changeGR[key] property.
    • If parsing fails: * The bad_field object is created and populated with the failed field name, and an error message with the expected date format. * The bad_field object is pushed into an array of invalid_fields for later processing.

Best Practices

  • Error Handling: Always wrap date parsing within a try...catch block to gracefully handle invalid date formats and return meaningful error messages.
  • Locale Awareness: Use gs.getDateTimeFormat() to dynamically fetch the appropriate format, making your code locale-aware.
  • Type Checking: Verify the data type in FIELDS[key].type, especially if your API handles a variety of input types.
  • Clear Error Messages: Provide clear error messages that specify the expected date format, helping users correct their inputs.
  • Date/Time vs Date: If you are only expecting a date value, you can use gs.getDateFormat() instead of gs.getDateTimeFormat().
  • Input Sanitization: Ensure the input values are sanitized before using the SimpleDateFormat as it is an external java class.

When to Use This Method

  • When you receive date and/or date/time values through a Scripted REST API.
  • When you need to validate that the date format adheres to user settings.
  • When you need to return meaningful error messages if the date formatting is not correct.
  • When you need to ensure only valid dates are used when creating or updating records.

Additional Considerations

  • Time Zones: If you're handling time zones, consider using GlideDateTime and it's conversion methods to ensure correct representation of timezones.
  • Asynchronous Processing: If you have a large number of fields, consider optimizing for performance by validating in an asynchronous process.
  • Script Includes: You can refactor the code into a Script Include for easier reuse across multiple Scripted REST APIs.

Conclusion

By using the Java SimpleDateFormat class in conjunction with gs.getDateTimeFormat(), you can implement robust date and date/time validation in your ServiceNow Scripted REST APIs. This approach will help ensure that you process date values correctly, according to your users locale, prevent data inconsistencies, and provide helpful error messages for debugging. Always test your APIs thoroughly to ensure proper functionality in various scenarios.