skip to Main Content

I’m trying to validate a user input for a datetime using date-fns:

import { isDate, isValid } from 'date-fns';

console.log('DATE:', stringVal);
console.log('IS_DATE:', isDate(new Date(stringVal)));
console.log('IS_VALID:', isValid(new Date(stringVal)));

This produces:

DATE: 2023-02-31 03:03:03
IS_DATE: true
IS_VALID: true

This seems to be incorrect because February 31, 2023 is not a valid date. What is the correct way of validating an ISO date string?

2

Answers


  1. Chosen as BEST ANSWER

    Looks like I can use the parseISO function:

    import { isDate, isValid, parseISO } from 'date-fns';
    
    if (!isDate(parseISO(stringVal)) || !isValid(parseISO(stringVal))) {
      throw new Error('Invalid date value');
    }
    

  2. There are a couple of things going on here.

    The date has already been corrected by the time you call isValid

    You are seeing if the return value of new Date('2023-02-31 03:03:03') is a valid date. At that point, the problem in the date string has already been corrected.

    console.log('DATE:', new Date(stringVal)); // Fri Mar 03 2023 03:03:03 
    console.log('IS_DATE:', isDate(new Date(stringVal))); // yes, Mar 03 is a date
    console.log('IS_VALID:', isValid(new Date(stringVal))); // yes, Mar 03 is valid
    

    The Date constructor is very optimistic – implementations are allowed to parse unexpected formats however they like:

    Date.parse() and the Date() constructor both accept strings in the date time string format as input. Furthermore, implementations are allowed to support other date formats when the input fails to match this format.

    You’d need to use a different parse function.

    Your string is not in ISO date format.

    Your string has spaces, and is missing the T indicator to separate the time and date parts. It should be 2023-02-31T03:03:03. Ideally, it should include timezone information too.


    A fix

    I recommend DateTime.fromISO from luxon, as it is strict about the format, and gives you clear reasoning for why the date didn’t parse:

    const maybeDate = DateTime.fromISO(`2023-02-31T03:03:03`);
    if(maybeDate.invalid) {
       console.log(maybeDate.invalid.reason); // unit out of range
       console.log(maybeDate.invalid.explanation) // you specified 31 (of type number) as a day, which is invalid
    }
    

    Note that if you use it with your original string, you get

    the input "2023-02-31 03:03:03" can't be parsed as ISO 8601
    

    because the original string isn’t in ISO format. You would get this error with valid dates written in non-ISO format too:

    DateTime.fromISO(`2023-02-28 03:03:03`)
    // the input "2023-02-28 03:03:03" can't be parsed as ISO 8601
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search