- Home
- /
- Tutorials
- /
- JavaScript Tutorial
- /
- JavaScript Date Pitfalls
JavaScript Dates
JavaScript Date Pitfalls
A few date behaviours catch out almost every JavaScript developer.
The Date API is one of the oldest parts of the language.
Knowing its four main traps prevents most date bugs.
Example
Example
javascript
const date = new Date(2026, 1, 30);
console.log(date.getMonth());
console.log(date.getDate());February has no 30th, so it rolled over into March.
No error was raised at all.
The Four Traps
Months start at 0.
Out-of-range values roll over silently.
An invalid date gives NaN rather than throwing.
Dates are mutable, so setters change the original.
Syntax
Syntax
javascript
Number.isNaN(date.getTime())This is how you check a date is valid.
Silent Rollover
This is occasionally useful but usually a surprise.
Example
Example
javascript
const date = new Date(Date.UTC(2026, 0, 32));
console.log(date.getUTCMonth());
console.log(date.getUTCDate());January 32 became February 1.
Invalid Dates
An unparseable string gives an Invalid Date, not an error.
Every getter on it returns NaN.
Example
Example
javascript
const date = new Date("not a date");
console.log(Number.isNaN(date.getTime()));
console.log(String(date));Always check before using a parsed date.
Checking Validity
A small helper is worth having.
Example
Example
javascript
function isValid(date) {
return date instanceof Date && !Number.isNaN(date.getTime());
}
console.log(isValid(new Date("2026-01-15")));
console.log(isValid(new Date("nonsense")));The output is true then false.
Date-Only Strings Are UTC
"2026-01-15" is parsed as UTC midnight.
In a negative timezone that reads as the previous day locally.
Example
Example
javascript
const date = new Date("2026-01-15");
console.log(date.getUTCDate());
console.log(date.toISOString().slice(0, 10));Reading it with getDate() could give 14 in some timezones.
Mutability Bites
A shared date changed in one place changes everywhere.
Example
Example
javascript
function addWeek(date) {
const copy = new Date(date.getTime());
copy.setUTCDate(copy.getUTCDate() + 7);
return copy;
}
const original = new Date(Date.UTC(2026, 0, 1));
const later = addWeek(original);
console.log(original.getUTCDate());
console.log(later.getUTCDate());Copying inside the function protects the caller's date.
Complete Example
Complete Example
html
<!DOCTYPE html>
<html>
<head>
<title>JavaScript Date Pitfalls</title>
</head>
<body>
<h1>Date Pitfalls</h1>
<p id="out"></p>
<script>
function isValid(date) {
return date instanceof Date && !Number.isNaN(date.getTime());
}
const rolled = new Date(Date.UTC(2026, 0, 32));
const broken = new Date("not a date");
document.getElementById("out").innerHTML =
"January 32 becomes month " + rolled.getUTCMonth() +
" day " + rolled.getUTCDate() +
"<br>Is the broken date valid: " + isValid(broken) +
"<br>February 30 exists: " + (new Date(Date.UTC(2026, 1, 30)).getUTCMonth() === 1);
</script>
</body>
</html>Try It Yourself
Run the above example in the Try It Editor.
Try another impossible date:
Use month 12 and see it roll into the next year.
Important Points
- Months start at 0.
- Out-of-range values roll over silently.
- An invalid date gives
NaN, not an error. - Check validity with
Number.isNaN(date.getTime()). - Dates are mutable, so copy before changing.
Conclusion
These four traps account for most JavaScript date bugs.
Validating a parsed date costs one line and saves a great deal.
For heavy date work, a modern library is worth the dependency.
