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: Using Date constructor for validationfunction 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:
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);}
// UsageisValidISODate("2020-01-23") // trueisValidISODate("Route 66") // falseisValidISODate("Beverly Hills, 90210") // falseisValidISODate("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:
import { parseISO, isValid } from 'date-fns';
// Strict ISO parsingfunction validateWithDateFns(dateString) { const date = parseISO(dateString); return isValid(date);}
// UsagevalidateWithDateFns("2020-01-23") // truevalidateWithDateFns("Route 66") // falsevalidateWithDateFns("invalid") // falseFor non-ISO formats, use parse with an explicit format string:
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;}
// UsageparseCustomFormat("01/23/2020", "MM/dd/yyyy"); // Valid Date objectparseCustomFormat("Route 66", "MM/dd/yyyy"); // nullparseCustomFormat("23-01-2020", "dd-MM-yyyy"); // Valid Date objectThis approach is explicit about the expected format. No surprises.
Method 3: Temporal API (Modern Browsers)
The Temporal API provides strict parsing by default:
// Temporal.PlainDate.from() throws on invalid inputfunction validateWithTemporal(dateString) { try { const date = Temporal.PlainDate.from(dateString); return date; } catch (e) { return null; }}
// UsagevalidateWithTemporal("2020-01-23") // PlainDate objectvalidateWithTemporal("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:
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;}
// UsagevalidateDateManual("2020-01-23") // truevalidateDateManual("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
| Method | Pros | Cons |
|---|---|---|
| Regex + Date | No dependencies | Limited to ISO format |
| date-fns | Many formats, well-tested | External dependency |
| Temporal | Modern, strict parsing | May need polyfill |
| Manual | Full control, no deps | More 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