SHARE
Facebook X Pinterest WhatsApp

Date Validation Using Moment.js

Written By
thumbnail
Rob Gravelle
Rob Gravelle
May 1, 2017

As you are likely painfully aware, dates are one of the most challenging types of user input to work with. Besides their history of being notoriously under-supported by native HTML, writing validation code can be a time consuming affair. While the HTML5 date input type and third-party widgets can help with the former, date validation can be bolstered by a good JavaScript Date library. The one that I have been using these days is Moment.js. It handles the parsing, manipulating, displaying, and validating of dates and times in JavaScript (JS). Since the HTML5 date type is still not widely supported by browsers, many site owners choose to accept dates via text inputs – a decision that places extra burden on the date validation, while strengthening the case for employing a good JS Date library. In today’s article, we’ll learn how to use Moment.js’s constructor and date validation methods to ensure that user-input dates are legal (i.e. correctly formatted) and valid.

It All Starts with the Parsing

How strictly you treat date strings goes hand-in-hand with your validation approach. For instance, native JS allows for rollovers so that a date of “Feb 31, 2000” is perfectly acceptable; the extra days will be added to the following month. Since Moment.js’s constructor acts as a wrapper for the plain ole’ JS Date object, it is naturally quite forgiving. In short, it checks if the string matches known ISO 8601 formats or RFC 2822 Date time format. Should those fail, it passes the input to the Date(string) constructor.

Due to inconsistent browser implementation of dates, your best bet is to supply your preferred format(s) to the Moment.js () constructor:

//Christmas day - one format
moment("1995-12-25", "YYYY-MM-DD");

//multiple formats
moment("12-25-1995", ["MM-DD-YYYY", "YYYY-MM-DD"]);

Following this rule of thumb makes the parser’s job a lot easier, which facilitates validation as well.

Strict Mode

The Moment.js parser’s forgiving nature offers the possibility of working with partial dates. Problem is, that same behavior can get you into trouble when dealing with exact dates. For instance, the following partial match is enough to qualify as a valid date:

moment('2016 is a date', 'YYYY-MM-DD');  //valid because the year matched! 

The way to avoid issues of that sort is to include the strict mode Boolean argument in the constructor invocation. A value of true specifies that the format and input must match exactly, including delimiters:

moment('2016 is a date', 'YYYY-MM-DD', true);  //no longer valid!

moment('2016/10/24', 'YYYY-MM-DD', true);  //neither is this! 

Testing for Date Legality

If you only want to know whether a date string was successfully converted into a proper date object, you can invoke the isValid() method on the moment instance variable:

var aDate   = moment(dateElt.value, 'YYYY-MM-DD', true);
var isValid = aDate.isValid();

It returns a boolean: true for valid, false for invalid.

Determining which Date Part Caused the Parser to Abort

Once isValid() comes back false, there is little point in continuing. The best you can do at that point is provide some details to your user. Enter the invalidAt() method. It returns a numeric index, which corresponds one of the following date parts:

  1. no overflow
  2. year
  3. month
  4. day
  5. hour
  6. minute
  7. seconds
  8. milliseconds

Here’s some code that would result in a value of “2” for an invalid day:

dateElt.value = '2000-02-30';
var aDate     = moment(dateElt.value, 'YYYY-MM-DD', true);
var invalidAt = aDate.invalidAt();  //returns 2 for invalid day

Accessing All of the Parsing Details

To get even more fine-grained details about parsing, you can invoke parsingFlags() on your invalid moment. It will produce an object much like this one:

//moment#parsingFlags for "34/1999extra..."
[object Object]
   {
      [functions]: ,
      __proto__: { },
      charsLeftOver: 11,
      empty: false,
      invalidFormat: false,
      invalidMonth: null,
      iso: false,
      nullInput: false,
      overflow: -1,
      unusedInput: [
         0: "34/",
         1: "extra...",
         length: 2
      ],
      unusedTokens: [
         0: "-",
         1: "MM",
         2: "-",
         3: "DD",
         length: 4
      ],
      userInvalidated: false
   }

That’s a lot of information, so let’s review each possible attribute and what it pertains to:

  • overflow: An overflow of a date field, such as a 13th month, a 32nd day of the month (or a 29th of February on non-leap years), a 367th day of the year, etc. overflow contains the index of the invalid unit to match #invalidAt (see below); -1 means no overflow.
  • invalidMonth: An invalid month name, such as moment('Marbruary', 'MMMM');. Contains the invalid month string itself, or else null.
  • empty: An input string that contains nothing parsable, such as moment('this is nonsense');. Boolean.
  • nullInput: A null input, like moment(null);. Boolean.
  • invalidFormat: An empty list of formats, such as moment('2013-05-25', []). Boolean.
  • userInvalidated: A date created explicitly as invalid, such as moment.invalid(). Boolean.
  • meridiem: Indicates what meridiem (AM/PM) was parsed, if any. String.
  • parsedDateParts: Returns an array of date parts parsed in descending order – i.e. parsedDateParts[0] === year. If no parts are present, but meridiem has value, date is invalid. Array.

Note that not all of the above attributes relate to every Date format and usage. For instance, invalidMonth only comes into play for written months. Moreover, nullInput is very unlikely to be triggered because in JavaScript nulls must be set explicitly.

Conclusion

Now that we know how to validate dates using Moment.js, the next step will be to bridge the UI to Moment.js’s date validation methods to display relevant contextual information to the user.

Recommended for you...

The Revolutionary ES6 Rest and Spread Operators
Rob Gravelle
Aug 23, 2022
Ahead of Time (AOT) Compilation in Angular
Tariq Siddiqui
Aug 16, 2022
Converting a JavaScript Object to a String
Rob Gravelle
Aug 14, 2022
Understanding Primitive Type Coercion in JavaScript
Rob Gravelle
Jul 28, 2022
HTML Goodies Logo

The original home of HTML tutorials. HTMLGoodies is a website dedicated to publishing tutorials that cover every aspect of being a web developer. We cover programming and web development tutorials on languages and technologies such as HTML, JavaScript, and CSS. In addition, our articles cover web frameworks like Angular and React.JS, as well as popular Content Management Systems (CMS) that include WordPress, Drupal, and Joomla. Website development platforms like Shopify, Squarespace, and Wix are also featured. Topics related to solid web design and Internet Marketing also find a home on HTMLGoodies, as we discuss UX/UI Design, Search Engine Optimization (SEO), and web dev best practices.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.