DEV Community

Kai Mercer
Kai Mercer

Posted on

Why your date shows up a day early: a one-minute check

A date that shows up as the day before is one of the most common small bugs in front-end code. Here is a one-minute check you can run in any console.

The check

const a = new Date("2026-10-25");        // date-only string
const b = new Date("2026-10-25T00:00");  // date-time string, no offset
Enter fullscreen mode Exit fullscreen mode

Per MDN's Date reference, when there is no time zone offset, date-only strings are read as UTC, and date-time strings are read as local time. MDN notes this comes from a historical spec error that could not be changed for web compatibility.

So the two lines above are different moments unless your machine is on UTC.

What I saw

I ran this in Node with the time zone set to America/Los_Angeles:

new Date("2026-10-25").toString()
// Sat Oct 24 2026 17:00:00 GMT-0700 (Pacific Daylight Time)

new Date("2026-10-25").getDate()
// 24

new Date("2026-10-25T00:00").toString()
// Sun Oct 25 2026 00:00:00 GMT-0700 (Pacific Daylight Time)
Enter fullscreen mode Exit fullscreen mode

Same calendar date typed in, but the first one is Saturday the 24th when you ask for the local day. On a UTC machine both lines print the 25th, which is why this often passes on a dev laptop or CI and fails for users in other zones.

Quick fixes

  • If the string is a calendar date with no time (a birthday, a due date), keep it as a string, or format it with timeZone: "UTC" so the same zone is used for parsing and display.
  • If you mean local midnight, build it from parts: new Date(2026, 9, 25) (months start at 0).
  • If you mean an exact moment, include an offset or Z in the string.

One test worth adding

Run the date logic once with the process in a zone far from UTC, for example TZ=America/Los_Angeles and TZ=Pacific/Auckland. If the displayed day changes between runs, there is a parse or display mismatch.

Which time zone do you use to test date code?

Top comments (3)

Collapse
 
marcusykim profile image
Marcus Kim •

Your new Date(2026, 9, 25) fix also needs a calendar-validity check if those parts come from a form. new Date(2026, 1, 29) silently becomes March 1, not an invalid date. I'd add that and April 31 to your Los Angeles/Auckland tests, with 2028-02-29 as the valid leap-year control. Reject changed year/month/day components before formatting. That keeps a timezone fix from quietly accepting a date the user never entered.

Collapse
 
mercerk17 profile image
Kai Mercer •

Good catch, thanks. I ran it in Node just now: new Date(2026, 1, 29) gives March 1, and new Date(2026, 3, 31) gives May 1, while new Date(2028, 1, 29) stays Feb 29. So the parts constructor rolls over instead of rejecting. Reading the year, month and day back and comparing them to the inputs is a cheap check, and those three cases belong in the test list.

Collapse
 
analista_83 profile image
Sammi De Blas •

The mismatch is at the boundary, not in the render. Storing the offset with the date is safer than parsing it back, and the check should assert the timezone where the value enters.