Thizzer
Thizzer

Reputation: 16653

Check if a string is a date value

What is an easy way to check if a value is a valid date, any known date format allowed.

For example I have the values 10-11-2009, 10/11/2009, 2009-11-10T07:00:00+0000 which should all be recognized as date values, and the values 200, 10, 350, which should not be recognized as a date value. What is the simplest way to check this, if this is even possible? Because timestamps would also be allowed.

Upvotes: 342

Views: 613462

Answers (25)

dogakorkmaz
dogakorkmaz

Reputation: 129

You can use this regex, change [1-5] if you want to include 2026..29:

^([1-2][1-9]|3[01])[\/\.-]((0[1-9])|1[0-2])[\/\.-](1\d{3}|20(([01]\d)|2[1-5]))$

Upvotes: 0

Jaber Alshami
Jaber Alshami

Reputation: 404

it is Simple:

// add you expresion
(/\d+-\d+-\d+/).test("2023-01-17 14:05:56.83419") // true

(/\d+-\d+-\d+/).test("202x-01-17 14:05:56.83419") // false

Upvotes: 0

A-Sharabiani
A-Sharabiani

Reputation: 19329

Here is an improved function that uses only Date.parse():

function isDate(dateToTest) {
    return isNaN(dateToTest) && !isNaN(Date.parse(dateToTest));
}

Note: Date.parse() will parse numbers: for example Date.parse(1) will return a date. So here we check if dateToTest is not a number then if it is a date.

Upvotes: 8

chuck fenley
chuck fenley

Reputation: 11

I believe this is the simplest working answer for date that contains only numbers:

var rst = Date.parse(sDate.replaceAll(" ",""));
if(rst===NaN) console.log("not a date");
else console.log("a great date")

By removing spaces you detect values like "hello 2" that are taken as a date. For the dates that contain strings like day name or month name ... I believe it is about string validation.

Upvotes: 0

MillCreeker
MillCreeker

Reputation: 49

I think the most straight forward solution would be

Date.parse(yourDate) > 0 ? true : false;

If it is not a valid date, it will be NaN, which is not greater than 0.

Upvotes: 0

Yuvraj Patil
Yuvraj Patil

Reputation: 8736

Does not work consistently, watch out!

isDate('Leyweg 1') returns true on Chrome (Firefox returns false) 🤔

Read: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse (Date.parse is called under the hood when invoking like so: new Date(someDateString).


Original answer:

function isDate(dateStr) {
  return !isNaN(new Date(dateStr).getDate());
}
  • This will work on any browser since it does not rely on "Invalid Date" check.
  • This will work with legacy code before ES6.
  • This will work without any library.
  • This will work regardless of any date format.
  • This does not rely on Date.parse which fails the purpose when values like "Spiderman 22" are in date string.
  • This does not ask us to write any RegEx.

Upvotes: 22

MadJoRR
MadJoRR

Reputation: 486

Here is what one could use to validate that the input is a number or a string that can be converted to a date object.

It covers the following cases:

  1. catching whatever input leads to "Invalid Date" date constructor result;
  2. catching the cases where the date is "valid" from technical point of view, but it is not valid from business logic point of view, like
  • new Date(null).getTime(): 0
  • new Date(true).getTime(): 1
  • new Date(-3.14).getTime(): -3
  • new Date(["1", "2"]).toDateString(): Tue Jan 02 2001
  • new Date([1, 2]).toDateString(): Tue Jan 02 2001
function checkDateInputValidity(input, lowerLimit, upperLimit) {
    // make sure the input is a number or string to avoid false positive correct dates:
    if (...) {
        return false
    }
    // create the date object:
    const date = new Date(input)
    // check if the Date constructor failed:
    if (date.toDateString() === 'Invalid Date') {
        return false
    }
    // check if the Date constructor succeeded, but the result is out of range:
    if (date < new Date(lowerLimit) || date > new Date(upperLimit)) {
        return false
    }
    return true
}

// const low = '2021-12-31T23:59:59'
// const high = '2025-01-01T00:00:00'

Upvotes: -1

itzhar
itzhar

Reputation: 13031

i find this solution very good:

const DateTime = require('luxon').DateTime;

isDateValid(stringDate) {
  let date = DateTime.fromFormat(stringDate, 'd-M-y');
  if (date.invalid === null) {
    return date.toJSDate();
  }
  date = DateTime.fromFormat(stringDate, 'd,M,y');
  if (date.invalid === null) {
    return date.toJSDate();
  }
  date = DateTime.fromFormat(stringDate, 'y-M-d');
  if (date.invalid === null) {
    return date.toJSDate();
  }
  date = DateTime.fromFormat(stringDate, 'y,M,d');
  if (date.invalid === null) {
    return date.toJSDate();
  }
  date = DateTime.fromFormat(stringDate, 'y.M.d');
  if (date.invalid === null) {
    return date.toJSDate();
  }
  date = DateTime.fromFormat(stringDate, 'd.M.y');
  if (date.invalid === null) {
    return date.toJSDate();
  }
  date = DateTime.fromFormat(stringDate, 'y/M/d');
  if (date.invalid === null) {
    return date.toJSDate();
  }
  date = DateTime.fromFormat(stringDate, 'd/M/y');
  if (date.invalid === null) {
    return date.toJSDate();
  }
  return false;
}

isDateValid('30.12.86'); //true
isDateValid('30/12/86'); //true
isDateValid('86-12-40'); //false

and you can easily add more formats

Upvotes: 1

Asmor
Asmor

Reputation: 5181

Would Date.parse() suffice?

See its relative MDN Documentation page.

Date.parse returns a timestamp if string date is valid. Here are some use cases:

// /!\ from now (2021) date interpretation changes a lot depending on the browser
Date.parse('01 Jan 1901 00:00:00 GMT') // -2177452800000
Date.parse('01/01/2012') // 1325372400000
Date.parse('153') // NaN (firefox) -57338928561000 (chrome)
Date.parse('string') // NaN
Date.parse(1) // NaN (firefox) 978303600000 (chrome)
Date.parse(1000) // -30610224000000 from 1000 it seems to be treated as year
Date.parse(1000, 12, 12) // -30610224000000 but days and month are not taken in account like in new Date(year, month,day...)
Date.parse(new Date(1970, 1, 0)) // 2588400000
// update with edge cases from comments
Date.parse('4.3') // NaN (firefox) 986248800000 (chrome)
Date.parse('2013-02-31') // NaN (firefox) 1362268800000 (chrome)
Date.parse("My Name 8") // NaN (firefox) 996616800000 (chrome)

Upvotes: 77

Janine White
Janine White

Reputation: 489

This function verifies that the input string in the format m/d/yyyy or mm/dd/yyyy can be converted to a date and that the date is a valid date matching the input string. Add more conditional checks to verify additional formats.

/**
 * Verify if a string is a date
 * @param {string} sDate - string that should be formatted m/d/yyyy or mm/dd/yyyy
 * @return {boolean} whether string is a valid date
 */
function isValidDate(sDate) {
  let newDate = new Date(sDate);
  console.log(sDate + " date conversion: " + newDate);
  let isDate = (!isNaN(newDate.getTime()));
  console.log(sDate + " is a date: " + isDate);
  if (isDate) {
    let firstSlash = sDate.indexOf("/");
    let secondSlash = sDate.indexOf("/",firstSlash+1);
    let originalDateString = parseInt(sDate.slice(0,firstSlash),10) + "/" + parseInt(sDate.slice(firstSlash+1,secondSlash),10) + "/" + parseInt(sDate.slice(secondSlash+1),10);
    let newDateString = (newDate.getMonth()+1) + "/" + (newDate.getDate()) + "/" + (newDate.getFullYear());
    isDate = (originalDateString == newDateString);
    console.log(originalDateString + " matches " + newDateString + ": " + isDate);
  }
  return isDate;
}

Upvotes: -1

kano
kano

Reputation: 5920

I feel none of the answers correctly understood what the OP asked. The issue here is that JavaScript can parse any number as a valid date, since the Date object can parse a string like '3000' as the year and will return a valid Date instance:

new Date('3000')

> Wed Jan 01 3000 02:00:00 GMT+0200 (Eastern European Standard Time)

To solve this, we can use the Day.js library's parsing method in strict mode by passing in a third argument. It's documented in their String + Format page. In order for parsing to work based on a format, we must also enable the CustomParseFormat plugin. I'm assuming you can use ESM imports here or have a compiler like Webpack set up

import dayjs from 'dayjs'
import formatParser from 'dayjs/plugin/customParseFormat'

dayjs.extend(formatParser)

dayjs('3000', 'YYYY-MM-DD', true).isValid()

> false

Upvotes: 4

Neil Girardi
Neil Girardi

Reputation: 4923

This is how I solved this problem in an app I'm working on right now:

updated based on feedback from krillgar:

var isDate = function(date) {
    return (new Date(date) !== "Invalid Date") && !isNaN(new Date(date));
}

Upvotes: 98

Nikhil Zurunge
Nikhil Zurunge

Reputation: 766

By referring to all of the above comments, I have come to a solution.

This works if the Date passed is in ISO format or need to manipulate for other formats.

var isISO = "2018-08-01T18:30:00.000Z";

if (new Date(isISO) !== "Invalid Date" && !isNaN(new Date(isISO))) {
    if(isISO == new Date(isISO).toISOString()) {
        console.log("Valid date");
    } else {
        console.log("Invalid date");
    }
} else {
    console.log("Invalid date");
}

You can play here on JSFiddle.

Upvotes: 9

m.steini
m.steini

Reputation: 21

Ok, this is an old question, but I found another solution while checking the solutions here. For me works to check if the function getTime() is present at the date object:

const checkDate = new Date(dateString);

if (typeof checkDate.getTime !== 'function') {
  return;
}

Upvotes: 0

jwerre
jwerre

Reputation: 9584

How about something like this? It will test if it is a Date object or a date string:

function isDate(value) {
    var dateFormat;
    if (toString.call(value) === '[object Date]') {
        return true;
    }
    if (typeof value.replace === 'function') {
        value.replace(/^\s+|\s+$/gm, '');
    }
    dateFormat = /(^\d{1,4}[\.|\\/|-]\d{1,2}[\.|\\/|-]\d{1,4})(\s*(?:0?[1-9]:[0-5]|1(?=[012])\d:[0-5])\d\s*[ap]m)?$/;
    return dateFormat.test(value);
}

I should mention that this doesn't test for ISO formatted strings but with a little more work to the RegExp you should be good.

Upvotes: 12

lpradhap
lpradhap

Reputation: 653

Use Regular expression to validate it.

isDate('2018-08-01T18:30:00.000Z');

isDate(_date){
        const _regExp  = new RegExp('^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$');
        return _regExp.test(_date);
    }

Upvotes: 11

peekolo
peekolo

Reputation: 342

I know it's an old question but I faced the same problem and saw that none of the answers worked properly - specifically weeding out numbers (1,200,345,etc..) from dates, which is the original question. Here is a rather unorthodox method I could think of and it seems to work. Please point out if there are cases where it will fail.

if(sDate.toString() == parseInt(sDate).toString()) return false;

This is the line to weed out numbers. Thus, the entire function could look like:

function isDate(sDate) {  
  if(sDate.toString() == parseInt(sDate).toString()) return false; 
  var tryDate = new Date(sDate);
  return (tryDate && tryDate.toString() != "NaN" && tryDate != "Invalid Date");  
}

console.log("100", isDate(100));
console.log("234", isDate("234"));
console.log("hello", isDate("hello"));
console.log("25 Feb 2018", isDate("25 Feb 2018"));
console.log("2009-11-10T07:00:00+0000", isDate("2009-11-10T07:00:00+0000"));

Upvotes: 5

rsp
rsp

Reputation: 111316

2015 Update

It is an old question but other new questions like:

get closed as duplicates of this one, so I think it's important to add some fresh info here. I'm writing it because I got scared thinking that people actually copy and paste some of the code posted here and use it in production.

Most of the answers here either use some complex regular expressions that match only some very specific formats and actually do it incorrectly (like matching January 32nd while not matching actual ISO date as advertised - see demo) or they try to pass anything to the Date constructor and wish for the best.

Using Moment

As I explained in this answer there is currently a library available for that: Moment.js

It is a library to parse, validate, manipulate, and display dates in JavaScript, that has a much richer API than the standard JavaScript date handling functions.

It is 12kB minified/gzipped and works in Node.js and other places:

bower install moment --save # bower
npm install moment --save   # npm
Install-Package Moment.js   # NuGet
spm install moment --save   # spm
meteor add momentjs:moment  # meteor

Using Moment you can be very specific about checking valid dates. Sometimes it is very important to add some clues about the format that you expect. For example, a date such as 06/22/2015 looks like a valid date, unless you use a format DD/MM/YYYY in which case this date should be rejected as invalid. There are few ways how you can tell Moment what format you expect, for example:

moment("06/22/2015", "MM/DD/YYYY", true).isValid(); // true
moment("06/22/2015", "DD/MM/YYYY", true).isValid(); // false

The true argument is there so the Moment won't try to parse the input if it doesn't exactly conform to one of the formats provided (it should be a default behavior in my opinion).

You can use an internally provided format:

moment("2015-06-22T13:17:21+0000", moment.ISO_8601, true).isValid(); // true

And you can use multiple formats as an array:

var formats = [
    moment.ISO_8601,
    "MM/DD/YYYY  :)  HH*mm*ss"
];
moment("2015-06-22T13:17:21+0000", formats, true).isValid(); // true
moment("06/22/2015  :)  13*17*21", formats, true).isValid(); // true
moment("06/22/2015  :(  13*17*21", formats, true).isValid(); // false

See: DEMO.

Other libraries

If you don't want to use Moment.js, there are also other libraries:

2016 Update

I created the immoment module that is like (a subset of) Moment but without surprises caused by mutation of existing objects (see the docs for more info).

2018 Update

Today I recommend using Luxon for date/time manipulation instead of Moment, which (unlike Moment) makes all object immutable so there are no nasty surprises related to implicit mutation of dates.

More info

See also:

A series of articles by Rob Gravelle on JavaScript date parsing libraries:

Bottom line

Of course anyone can try to reinvent the wheel, write a regular expression (but please actually read ISO 8601 and RFC 3339 before you do it) or call buit-in constructors with random data to parse error messages like 'Invalid Date' (Are you sure this message is exactly the same on all platforms? In all locales? In the future?) or you can use a tested solution and use your time to improve it, not reinvent it. All of the libraries listed here are open source, free software.

Upvotes: 364

None of the answers here address checking whether the date is invalid such as February 31. This function addresses that by checking if the returned month is equivalent to the original month and making sure a valid year was presented.

//expected input dd/mm/yyyy or dd.mm.yyyy or dd-mm-yyyy
function isValidDate(s) {
  var separators = ['\\.', '\\-', '\\/'];
  var bits = s.split(new RegExp(separators.join('|'), 'g'));
  var d = new Date(bits[2], bits[1] - 1, bits[0]);
  return d.getFullYear() == bits[2] && d.getMonth() + 1 == bits[1];
} 

Upvotes: 15

Peter DK
Peter DK

Reputation: 31

This callable function works perfectly, returns true for valid date. Be sure to call using a date on ISO format (yyyy-mm-dd or yyyy/mm/dd):

function validateDate(isoDate) {

    if (isNaN(Date.parse(isoDate))) {
        return false;
    } else {
        if (isoDate != (new Date(isoDate)).toISOString().substr(0,10)) {
            return false;
        }
    }
    return true;
}

Upvotes: 2

kheya
kheya

Reputation: 7612

This is how I end up doing it. This will not cover all formats. You have to adjust accordingly. I have control on the format, so it works for me

function isValidDate(s) {
            var dt = "";
            var bits = [];
            if (s && s.length >= 6) {
                if (s.indexOf("/") > -1) {
                    bits = s.split("/");
                }
                else if (s.indexOf("-") > -1) {
                    bits = s.split("-");
                }
                else if (s.indexOf(".") > -1) {
                    bits = s.split(".");
                }
                try {
                    dt = new Date(bits[2], bits[0] - 1, bits[1]);
                } catch (e) {
                    return false;
                }
                return (dt.getMonth() + 1) === parseInt(bits[0]);
            } else {
                return false;
            }
        }

Upvotes: -2

krillgar
krillgar

Reputation: 12805

new Date(date) === 'Invalid Date' only works in Firefox and Chrome. IE8 (the one I have on my machine for testing purposes) gives NaN.

As was stated to the accepted answer, Date.parse(date) will also work for numbers. So to get around that, you could also check that it is not a number (if that's something you want to confirm).

var parsedDate = Date.parse(date);

// You want to check again for !isNaN(parsedDate) here because Dates can be converted
// to numbers, but a failed Date parse will not.
if (isNaN(date) && !isNaN(parsedDate)) {
    /* do your work */
}

Upvotes: 37

kiranvj
kiranvj

Reputation: 34107

I would do this

var myDateStr= new Date("2015/5/2");

if( ! isNaN ( myDateStr.getMonth() )) {
    console.log("Valid date");
}
else {
    console.log("Invalid date");
}

Play here

Upvotes: 2

Kishore Relangi
Kishore Relangi

Reputation: 2034

is it fine to check for a Date related function is available for the object to find whether it is a Date object or not ?

like

var l = new Date();
var isDate = (l.getDate !== undefined) ? true; false;

Upvotes: 1

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48600

Here's a minimalist version.

var isDate = function (date) {
    return!!(function(d){return(d!=='Invalid Date'&&!isNaN(d))})(new Date(date));
}

Upvotes: 0

Related Questions