Skip to content

How to Properly Validate Date Strings in JavaScript (Without the Pitfalls)

Purpose

This post demonstrates how to properly validate date strings in JavaScript without falling into the Date constructor trap.

Environment

  • Node.js v20.x
  • date-fns v3.x
  • Modern browsers (Chrome 120+, Firefox 120+, Safari 17+)

The Problem with Date Constructor Validation

Many developers use the Date constructor to validate date strings. This is a mistake:

wrong-validator.js
// WRONG: Using Date constructor for validation
function isValidDate(str) {
return !isNaN(new Date(str).getTime());
}
isValidDate("2020-01-23") // true (expected)
isValidDate("Route 66") // true! (returns year 1966)
isValidDate("Beverly Hills, 90210") // true! (returns year 90,210)
isValidDate("Today is 2020-01-23") // true! (extracts date from text)

The Date constructor is NOT a validator. It’s a parser that tries to be helpful by extracting date-like patterns from any string.

How to Validate Date Strings

Method 1: Regex + Date Constructor (ISO 8601 Only)

For simple cases with ISO 8601 format (YYYY-MM-DD), use regex validation first:

iso-validator.js
function isValidISODate(dateString) {
// Strict ISO 8601 regex
const isoRegex = /^\d{4}-\d{2}-\d{2}$/;
if (!isoRegex.test(dateString)) {
return false;
}
const date = new Date(dateString);
const timestamp = date.getTime();
// Check for Invalid Date
return !isNaN(timestamp);
}
// Usage
isValidISODate("2020-01-23") // true
isValidISODate("Route 66") // false
isValidISODate("Beverly Hills, 90210") // false
isValidISODate("2020-13-45") // false (invalid month/day)
isValidISODate("2020-02-30") // false (Feb 30 doesn't exist)

I first check the format with regex. Only if it matches ISO 8601 do I parse with Date.

Method 2: Using date-fns

For production code, I recommend date-fns. It provides parseISO and isValid functions:

date-fns-validator.js
import { parseISO, isValid } from 'date-fns';
// Strict ISO parsing
function validateWithDateFns(dateString) {
const date = parseISO(dateString);
return isValid(date);
}
// Usage
validateWithDateFns("2020-01-23") // true
validateWithDateFns("Route 66") // false
validateWithDateFns("invalid") // false

For non-ISO formats, use parse with an explicit format string:

date-fns-custom-format.js
import { parse, isValid } from 'date-fns';
function parseCustomFormat(dateString, format) {
const referenceDate = new Date();
const date = parse(dateString, format, referenceDate);
return isValid(date) ? date : null;
}
// Usage
parseCustomFormat("01/23/2020", "MM/dd/yyyy"); // Valid Date object
parseCustomFormat("Route 66", "MM/dd/yyyy"); // null
parseCustomFormat("23-01-2020", "dd-MM-yyyy"); // Valid Date object

This approach is explicit about the expected format. No surprises.

Method 3: Temporal API (Modern Browsers)

The Temporal API provides strict parsing by default:

temporal-validator.js
// Temporal.PlainDate.from() throws on invalid input
function validateWithTemporal(dateString) {
try {
const date = Temporal.PlainDate.from(dateString);
return date;
} catch (e) {
return null;
}
}
// Usage
validateWithTemporal("2020-01-23") // PlainDate object
validateWithTemporal("Route 66") // null (throws error)
validateWithTemporal("invalid") // null (throws error)

Note: As of 2026, Temporal may require a polyfill in some browsers. Check MDN for current browser support.

Method 4: Manual Validation (No Dependencies)

If you can’t add dependencies, validate manually:

manual-validator.js
function validateDateManual(dateString) {
// Split and validate components
const parts = dateString.split('-');
if (parts.length !== 3) return false;
const [year, month, day] = parts.map(Number);
// Check for NaN
if (isNaN(year) || isNaN(month) || isNaN(day)) return false;
// Check ranges
if (year < 1000 || year > 9999) return false;
if (month < 1 || month > 12) return false;
// Get days in month (handles leap years)
const daysInMonth = new Date(year, month, 0).getDate();
if (day < 1 || day > daysInMonth) return false;
return true;
}
// Usage
validateDateManual("2020-01-23") // true
validateDateManual("Route 66") // false (split fails)
validateDateManual("2020-13-01") // false (month out of range)
validateDateManual("2020-02-30") // false (Feb has 28 or 29 days)

Comparison

MethodProsCons
Regex + DateNo dependenciesLimited to ISO format
date-fnsMany formats, well-testedExternal dependency
TemporalModern, strict parsingMay need polyfill
ManualFull control, no depsMore code to maintain

Summary

In this post, I showed four methods to validate date strings in JavaScript. The key point is: never use the Date constructor for validation. For simple cases, use regex validation for ISO 8601 format. For complex date handling, use date-fns. Always validate the format before parsing.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments