74

I'm trying to test to make sure a date is valid in the sense that if someone enters 2/30/2011 then it should be wrong.

How can I do this with any date?

Jesper Rønn-Jensen
  • 106,591
  • 44
  • 118
  • 155
Seth Duncan
  • 1,255
  • 2
  • 13
  • 31
  • @Mitch - right in the bull's eye :) – Andrey Apr 28 '11 at 00:25
  • 2
    @Mitch - the OP wants to know if it's a valid date, not a valid date object. e.g. `new Date('2011/5/33')` will create a date object, but the date wouldn't be considered valid. – RobG Apr 28 '11 at 00:34
  • 1
    Can you please open it again? There may be other, better answers. – RobG Apr 28 '11 at 01:32
  • @MitchWheat Since these two are different questions and this question has a good answer, I think, you have responsibility to reopen it. [This question has very good view count as well.] – LCJ Dec 21 '12 at 12:42
  • This is an obscenely complicated question. First, formatting: 25/2/2011 is a perfectly good date in much of Europe. But is 2/12/2013 Dec.2 or Feb 12? Second: if you want it to work historically, there are ancient leaders who invalidated certain dates by messing with the calendar. – Paul Aug 13 '13 at 05:56
  • Check this question http://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript – Daan Jul 27 '15 at 06:54

11 Answers11

128

One simple way to validate a date string is to convert to a date object and test that, e.g.

// Expect input as d/m/y
function isValidDate(s) {
  var bits = s.split('/');
  var d = new Date(bits[2], bits[1] - 1, bits[0]);
  return d && (d.getMonth() + 1) == bits[1];
}

['0/10/2017','29/2/2016','01/02'].forEach(function(s) {
  console.log(s + ' : ' + isValidDate(s))
})

When testing a Date this way, only the month needs to be tested since if the date is out of range, the month will change. Same if the month is out of range. Any year is valid.

You can also test the bits of the date string:

function isValidDate2(s) {
  var bits = s.split('/');
  var y = bits[2],
    m = bits[1],
    d = bits[0];
  // Assume not leap year by default (note zero index for Jan)
  var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

  // If evenly divisible by 4 and not evenly divisible by 100,
  // or is evenly divisible by 400, then a leap year
  if ((!(y % 4) && y % 100) || !(y % 400)) {
    daysInMonth[1] = 29;
  }
  return !(/\D/.test(String(d))) && d > 0 && d <= daysInMonth[--m]
}

['0/10/2017','29/2/2016','01/02'].forEach(function(s) {
  console.log(s + ' : ' + isValidDate2(s))
})
RobG
  • 142,382
  • 31
  • 172
  • 209
  • 6
    Note: dateformat used for example 2 is dd/mm/yyyy and not mm/dd/yyyy – Stefan Steiger Oct 11 '12 at 07:09
  • The first solution presented is not really complete. It returns true for '367/1/2000' for example while it's not really a valid date. Take a look at my answer which includes a regular expression check before parsing the date and comparing the month. – rosenfeld Jun 27 '18 at 21:18
10

Does first function isValidDate(s) proposed by RobG will work for input string '1/2/'? I think NOT, because the YEAR is not validated ;(

My proposition is to use improved version of this function:

//input in ISO format: yyyy-MM-dd
function DatePicker_IsValidDate(input) {
        var bits = input.split('-');
        var d = new Date(bits[0], bits[1] - 1, bits[2]);
        return d.getFullYear() == bits[0] && (d.getMonth() + 1) == bits[1] && d.getDate() == Number(bits[2]);
}
Piotr Kwiatek
  • 687
  • 8
  • 10
  • You should think otherwise, the function I posted only needs to check the month.Checking more than that is redundant since if either the day or month are out of range, the month will change. Testing the year is moot since any year may or may not be valid and its value will only change if the month also changes. – RobG Mar 28 '16 at 23:22
  • @RobG - I think that Piotr's point is that the year should be checked in case the "Year" is `null` or is non-numeric. – Kevin Fegan May 12 '16 at 06:23
  • @KevinFegan—if that's so, then the result will be an invalid date, and the month check will (correctly) fail. ;-) – RobG May 12 '16 at 08:30
  • 1
    Rob, experimenting with your solution I noticed `01/02` returns true. – adi518 Feb 11 '17 at 22:46
  • @adi518—added '01/02' as a test to both examples, the first returns false, the second true. I’ll leave it up to others if they want to change that or not. – RobG Jun 26 '18 at 04:09
  • It is a good practice to validate the date syntax using a [regex](https://stackoverflow.com/a/51231/8407719) first anyway. So I would prefer the answer posted by @RobG – Kewal Shah May 09 '20 at 11:39
5

I recommend to use moment.js. Only providing date to moment will validate it, no need to pass the dateFormat.

var date = moment("2016-10-19");

And then date.isValid() gives desired result.

Se post HERE

  • Moment is a great library and I actually use it for most of my current web projects, however I was trying to accomplish this originally without any additional libraries. Thanks for the contribution though, I highly reccomend Moment.js – Seth Duncan Feb 12 '18 at 18:19
  • 1
    This only works if the date format is in a 'RFC2822 or ISO' format. Otherwise it passes down to the original Date constructor. So it would not solve op's problem: `moment('2/30/2011').isValid()` returns `true`. – BJury Apr 12 '19 at 13:25
  • Re "*no need to pass the dateFormat*", you should always pass the format. If it's not the default moment.js format, it falls back to the built–in parser, so no better than `new Date(string)`. – RobG May 07 '20 at 22:40
  • moment.js is now obsolete – Merc Mar 27 '22 at 01:02
  • (You can try Luxon) – Merc Mar 27 '22 at 01:02
4

This solution does not address obvious date validations such as making sure date parts are integers or that date parts comply with obvious validation checks such as the day being greater than 0 and less than 32. This solution assumes that you already have all three date parts (year, month, day) and that each already passes obvious validations. Given these assumptions this method should work for simply checking if the date exists.

For example February 29, 2009 is not a real date but February 29, 2008 is. When you create a new Date object such as February 29, 2009 look what happens (Remember that months start at zero in JavaScript):

console.log(new Date(2009, 1, 29));

The above line outputs: Sun Mar 01 2009 00:00:00 GMT-0800 (PST)

Notice how the date simply gets rolled to the first day of the next month. Assuming you have the other, obvious validations in place, this information can be used to determine if a date is real with the following function (This function allows for non-zero based months for a more convenient input):

var isActualDate = function (month, day, year) {
    var tempDate = new Date(year, --month, day);
    return month === tempDate.getMonth();
};

This isn't a complete solution and doesn't take i18n into account but it could be made more robust.

Luke Cordingley
  • 665
  • 4
  • 11
4
var isDate_ = function(input) {
        var status = false;
        if (!input || input.length <= 0) {
          status = false;
        } else {
          var result = new Date(input);
          if (result == 'Invalid Date') {
            status = false;
          } else {
            status = true;
          }
        }
        return status;
      }

this function returns bool value of whether the input given is a valid date or not. ex:

if(isDate_(var_date)) {
  // statements if the date is valid
} else {
  // statements if not valid
}
Dhayalan
  • 57
  • 2
2

I just do a remake of RobG solution

var daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
var isLeap = new Date(theYear,1,29).getDate() == 29;

if (isLeap) {
  daysInMonth[1] = 29;
}
return theDay <= daysInMonth[--theMonth]
Community
  • 1
  • 1
Derekthar
  • 533
  • 2
  • 12
  • 23
1

This is ES6 (with let declaration).

function checkExistingDate(year, month, day){ // year, month and day should be numbers
     // months are intended from 1 to 12
    let months31 = [1,3,5,7,8,10,12]; // months with 31 days
    let months30 = [4,6,9,11]; // months with 30 days
    let months28 = [2]; // the only month with 28 days (29 if year isLeap)

    let isLeap = ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);

    let valid = (months31.indexOf(month)!==-1 && day <= 31) || (months30.indexOf(month)!==-1 && day <= 30) || (months28.indexOf(month)!==-1 && day <= 28) || (months28.indexOf(month)!==-1 && day <= 29 && isLeap);

    return valid; // it returns true or false
}

In this case I've intended months from 1 to 12. If you prefer or use the 0-11 based model, you can just change the arrays with:

let months31 = [0,2,4,6,7,9,11];
let months30 = [3,5,8,10];
let months28 = [1];

If your date is in form dd/mm/yyyy than you can take off day, month and year function parameters, and do this to retrieve them:

let arrayWithDayMonthYear = myDateInString.split('/');
let year = parseInt(arrayWithDayMonthYear[2]);
let month  = parseInt(arrayWithDayMonthYear[1]);
let day = parseInt(arrayWithDayMonthYear[0]);
Alice
  • 31
  • 6
0

My function returns true if is a valid date otherwise returns false :D

function isDate  (day, month, year){
 if(day == 0 ){
  return false;
 }
 switch(month){
  case 1: case 3: case 5: case 7: case 8: case 10: case 12:
   if(day > 31)
    return false;
   return true;
  case 2:
   if (year % 4 == 0)
    if(day > 29){
     return false;
    }
    else{
     return true;
    }
   if(day > 28){
    return false;
   }
   return true;
  case 4: case 6: case 9: case 11:
   if(day > 30){
    return false;
   }
   return true;
  default:
   return false;
 }
}

console.log(isDate(30, 5, 2017));
console.log(isDate(29, 2, 2016));
console.log(isDate(29, 2, 2015));
0

It's unfortunate that it seems JavaScript has no simple way to validate a date string to these days. This is the simplest way I can think of to parse dates in the format "m/d/yyyy" in modern browsers (that's why it doesn't specify the radix to parseInt, since it should be 10 since ES5):

const dateValidationRegex = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
function isValidDate(strDate) {
  if (!dateValidationRegex.test(strDate)) return false;
  const [m, d, y] = strDate.split('/').map(n => parseInt(n));
  return m === new Date(y, m - 1, d).getMonth() + 1;
}

['10/30/2000abc', '10/30/2000', '1/1/1900', '02/30/2000', '1/1/1/4'].forEach(d => {
  console.log(d, isValidDate(d));
});
rosenfeld
  • 1,730
  • 15
  • 19
0

Hi Please find the answer below.this is done by validating the date newly created

var year=2019;
var month=2;
var date=31;
var d = new Date(year, month - 1, date);
if (d.getFullYear() != year
        || d.getMonth() != (month - 1)
        || d.getDate() != date) {
    alert("invalid date");
    return false;
}
-1
function isValidDate(year, month, day) {
        var d = new Date(year, month - 1, day, 0, 0, 0, 0);
        return (!isNaN(d) && (d.getDate() == day && d.getMonth() + 1 == month && d.getYear() == year));
    }
Himanshu
  • 4,327
  • 16
  • 31
  • 39
mathew
  • 11