jquery-validation / jquery-validation

jQuery Validation Plugin library sources

Home Page:https://jqueryvalidation.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Date validation failure.

lgnl272 opened this issue · comments

Your environment

  • Version of JQV: 1.19
  • Browser name and version: Google Chrome 107.0.5304.107 (Build oficial) (64 bits)

Current behavior

Validator allows any kind of dates even considerating day 30 in February

Expected behavior

Validator must return an error message.

Live demo

Try to validate 1983-02-30 and validator doesn't show anny error message

I believe that you used the Date method, which has been deprecated in favour of DateISO. I get that from the comment in
#1845.

I'm using the DateISO method

@lgnl272 Please provide a jsfiddle link

Duplicate bug: #276
DateISO only does structure checks, where 1983-02-30 is a valid DateISO structure.
It is an invalid Date.

I find it interesting that the 'date' validator is deprecated in favor for date ISO which is a standard notation/format.
There is no way to verify that the date is valid in time using ISO notation.

Probably need to implement ISO week date which is part of ISO 8061 so the date can be checked for two(2) things:

  • valid ISO notation
  • valid date/time exists

DateISO should be named DateISO8061 or DateISOFormat, then de-depricate the 'date' validator.

Date validator correctly errors on new Date('1983-02-30') as it should.

Reminds me of an old pull request: #2032

return this.optional( element ) || ( !/Invalid|NaN/.test( new Date( value ) ) && /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value ) );

adding the !/Invalid|NaN/.test( new Date( value ) check fixes the current use case.
Basically copied the test case for date: (that is being deprecated) and logically AND it with dateISO format.

Screen shot of test cases:

Screenshot 2023-01-06 at 3 07 55 PM

new Date (dateString) format includes date-only forms:
where dateString can be one of:

  • "YYYY"
  • "YYYY-MM"
  • "YYYY-MM-DD"

YYYY-MM-DD follows exactly as a Date only ISO format (not including time).
new Date(dateString) is ISO-8061 compliant.
Quote from MDN web docs "This is ISO-8601-compliant and will work reliably"

I'll add a push and create a pull request.

Disregard the above, I now see the problem with Date() and how different browsers interpret.
Bigger problem with JavaScript, not jquery-validate.

ChatGPT came up with this code, and it works for me in Firefox, Safari and Chrome.

/**
 * Checks if a given string is a valid date in the format MM/DD/YYYY.
 * @param {string} dateString - The string to validate.
 * @returns {boolean} True if the string is a valid date, false otherwise.
 */
function isValidDate(dateString) {
  const dateFormatRegex = /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/;

  // Check if the string matches the expected date format.
  if (!dateString.match(dateFormatRegex)) {
    // The string does not match the expected format.
    console.log( "The string does not match the expected format.");
    return false;
  }

  // Split the string into its component parts.
  const [year, month, day] = dateString.split('-').map(part => parseInt(part));

  // Check if the month is valid.
  if (month < 1 || month > 12) {
      console.log( "The month is not valid.");
    return false;
  }

  // Check if the day is valid for the given month and year.
  const daysInMonth = getDaysInMonth(month, year);
  if (day < 1 || day > daysInMonth) {
        console.log( "The day is not valid.");
    return false;
  }

  // The string is a valid date.
  return true;
}

/**
 * Returns the number of days in the given month for the given year.
 * @param {number} month - The month (1-12).
 * @param {number} year - The year.
 * @returns {number} The number of days in the given month for the given year.
 */
function getDaysInMonth(month, year) {
  if (month === 2 && isLeapYear(year)) {
    return 29;
  }
  return [31,28,31,30,31,30,31,31,30,31,30,31][month - 1];
}

/**
 * Checks if the given year is a leap year.
 * @param {number} year - The year.
 * @returns {boolean} True if the year is a leap year, false otherwise.
 */
function isLeapYear(year) {
  return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
}

Here is a jsfiddle: JS Fiddle 'isValidDate'

I have added a test case, grunt completes successful, all tests pass.

Questions:
I have created a new validator named 'isValidDate' using DateISO standards, should my new validator replace dateISO?
Should I submit PR as is, or wait for the above question answered?

I think this solution will close a lot of date issues.