Dev.to WebDev 🛠 Dev 👁 0 📖 1 min read

toISOString().slice(0, 10) is not today's date

A user reported that an invoice they issued on the 1st of the month was dated the 31st of the previous month. VAT reports in Israel are filed by calendar month, so this was not cosmetic. The invoice landed in the wrong r

A user reported that an invoice they issued on the 1st of the month was dated the 31st of the previous month. VAT reports in Israel are filed by calendar month, so this was not cosmetic. The invoice landed in the wrong reporting period.

The bug was one line:

const issueDate = new Date().toISOString().slice(0, 10);

toISOString() returns UTC. Israel is UTC+2 (UTC+3 in summer). Issue a document at 00:30 local time and UTC still says yesterday. The user gets a legal document carrying the wrong date, and nobody notices until an accountant does.

The fix is to format in the business's own timezone, not the server's and not UTC:

function localDateString(timeZone = 'Asia/Jerusalem') {
  return new Intl.DateTimeFormat('en-CA', { timeZone }).format(new Date());
}
// "2026-07-31", en-CA locale gives YYYY-MM-DD directly

Same rule on the backend. A Node server deployed in Frankfurt runs on UTC, so new Date().getDate() there is just as wrong as toISOString().

Two lessons that outlived the bug:

First, a fiscal date is a calendar day, not a timestamp. Store it as a plain YYYY-MM-DD string, not a Date. The moment you store midnight-UTC datetimes for date-only facts, every serialization boundary (database driver, JSON, ORM) is a new chance to shift the day. The "when exactly did this happen" question belongs to a separate audit timestamp in full ISO, with the timezone kept.

Second, decide which timezone owns the date once, and put the helper next to that decision. We centralized it into one localDateString() util on the client and one jerusalemToday() on the server, and banned raw toISOString().slice in review. The bug never came back.

This came out of building Slate, invoicing software for Israeli businesses, where a document's date decides which VAT period it belongs to. Any app that puts a date on a legal or financial record has this bug waiting if it formats dates through UTC.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.