Skip to content

Why Does JavaScript Parse 'Route 66' as a Date? Understanding Date Constructor Behavior

Problem

When I used JavaScript’s Date constructor to validate user input, I found that random strings like “Route 66” were accepted as valid dates:

new Date("Route 66")
// Sat Jan 01 1966 00:00:00 GMT-0500
new Date("Beverly Hills, 90210")
// Mon Jan 01 90210 00:00:00 GMT-0500

This caused a bug where addresses and business names in our app were being displayed as dates.

Environment

  • Node.js v20.x
  • Chrome 120+ (V8 engine)
  • JavaScript ES2023

What happened?

We had a bug in our app. Addresses and business names were being converted to dates unexpectedly.

The root cause: we used the Date constructor as a fallback parser to catch unexpected date formats:

buggy-validator.js
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)

I thought the Date constructor would reject non-date strings. But it doesn’t. It tries to be helpful by extracting any numbers that could represent a date.

Here are more examples of this behavior:

date-parsing-examples.js
// Expected behavior
new Date("2020-01-23")
// Wed Jan 22 2020 19:00:00 GMT-0500 (ISO format, parsed as UTC)
// Unexpected behavior
new Date("Route 66")
// Sat Jan 01 1966 00:00:00 GMT-0500 (interprets 66 as year 1966)
new Date("Beverly Hills, 90210")
// Mon Jan 01 90210 00:00:00 GMT-0500 (year 90,210!)
new Date("Today is 2020-01-23")
// Thu Jan 23 2020 00:00:00 GMT-0500 (extracts date from sentence)

How to solve it?

I tried a few approaches.

Solution 1: Strict ISO 8601 Validation

The Date constructor only guarantees consistent parsing for ISO 8601 format (YYYY-MM-DD). For other formats, browsers behave differently.

iso-validator.js
function isValidISODate(str) {
// Strict ISO 8601 regex
const isoRegex = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/;
if (!isoRegex.test(str)) {
return false;
}
const date = new Date(str);
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)

This works for ISO dates. But what about other formats?

Solution 2: Use date-fns

For production code, I recommend using a dedicated date library. date-fns provides parseISO and isValid functions:

date-fns-validator.js
import { parseISO, isValid } from 'date-fns';
function parseDateSafely(str) {
try {
const date = parseISO(str);
return isValid(date) ? date : null;
} catch {
return null;
}
}
// Usage
parseDateSafely("2020-01-23") // Valid Date object
parseDateSafely("Route 66") // null

For non-ISO formats, date-fns has parse with explicit format strings:

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

The reason

Why does JavaScript behave this way?

1. Legacy Parser Design

The Date constructor uses a parser designed to be maximally helpful. It was created in the early days of the web when developers passed date strings in many formats. The parser tries to extract date-like patterns from almost any string.

2. Implementation-Defined Behavior

The ECMAScript spec only mandates parsing for ISO 8601 format. Everything else is “implementation-defined,” meaning each browser can parse however it wants:

ECMAScript Spec:
┌─────────────────┐
│ ISO 8601 Format │ → Spec-defined, consistent across browsers
└─────────────────┘
┌─────────────────┐
│ Other Formats │ → Implementation-defined, varies by browser
└─────────────────┘

3. Backward Compatibility

This behavior cannot change. Too many websites rely on the current parsing behavior. Changing it would break the web.

4. V8, SpiderMonkey, JavaScriptCore

Each JavaScript engine has its own legacy parser:

  • V8 (Chrome/Node.js)
  • SpiderMonkey (Firefox)
  • JavaScriptCore (Safari)

They may parse the same string differently.

Summary

In this post, I showed why JavaScript’s Date constructor accepts random strings as dates. The key point is: never use the Date constructor for validation. Use strict ISO 8601 validation with regex, or use a library like date-fns. For new projects, consider the Temporal API which provides cleaner date handling.

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