DEV Community

Cover image for 7 Date and Time Bugs That Keep Biting Developers (and How to Debug Them Fast)
Bellal Hossain
Bellal Hossain

Posted on

7 Date and Time Bugs That Keep Biting Developers (and How to Debug Them Fast)

Every developer has shipped a date bug. Usually it works on your machine, passes tests, and then fails for a user in another country at 11:30 PM on the last day of the month.

Here are seven of the most common date and time bugs, with short examples and fast ways to debug them.

1. Treating local time as universal time

A timestamp without a time zone is ambiguous. "2026-03-08 09:00" means nothing until you know where it was recorded.

Rule of thumb: store and transmit in UTC, convert to local time only when displaying.

When you're debugging a log line and need to compare it across regions, a world clock or time zone converter is quicker than doing the offset math in your head.

2. Parsing date strings inconsistently

In JavaScript, these two look almost identical but behave differently:

new Date("2026-03-08");          // parsed as UTC midnight
new Date("2026-03-08T00:00:00"); // parsed as LOCAL midnight
Enter fullscreen mode Exit fullscreen mode

A date-only ISO string is treated as UTC, while a date-time string without an offset is treated as local time. In a timezone behind UTC, the first one can display as the previous day.

Fix: always include an explicit offset or Z:

new Date("2026-03-08T00:00:00Z");
new Date("2026-03-08T00:00:00+06:00");
Enter fullscreen mode Exit fullscreen mode

If you're unsure what a string means, run it through a date and time conversion tool to see the UTC and local versions side by side.

3. Mixing seconds and milliseconds

Unix timestamps are usually in seconds. JavaScript's Date.now() returns milliseconds.

const seconds = Math.floor(Date.now() / 1000); // Unix time in seconds
const ms = Date.now();                         // milliseconds

new Date(seconds);        // wrong: lands in January 1970
new Date(seconds * 1000); // correct
Enter fullscreen mode Exit fullscreen mode

If a date shows up as 1970, you probably passed seconds where milliseconds were expected. A quick paste into a timestamp converter shows what a value really represents, and a 10-digit versus 13-digit value tells you the unit at a glance.

4. Assuming a day is always 24 hours

Daylight saving time breaks this. In regions that observe DST, a calendar day can be 23 or 25 hours long.

from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo

ny = ZoneInfo("America/New_York")
start = datetime(2026, 3, 7, 12, 0, tzinfo=ny)
end = start + timedelta(days=1)   # same wall-clock time next day

print(end)  # 2026-03-08 12:00:00-04:00
print((end.astimezone(timezone.utc) - start.astimezone(timezone.utc)))
# 23:00:00
Enter fullscreen mode Exit fullscreen mode

In 2026, US clocks spring forward on March 8, so "one day later" is only 23 hours of elapsed time here. Decide whether you mean "same time tomorrow" or "24 hours later," because they're different operations.

Also remember that DST rules differ by country, and some regions don't observe it at all. Before scheduling anything across regions, check the current offsets in a time zone tool.

5. Month overflow

Adding months is not the same as adding 30 days.

const d = new Date(2026, 0, 31); // Jan 31, 2026
d.setMonth(d.getMonth() + 1);
console.log(d.toDateString());   // Tue Mar 03 2026
Enter fullscreen mode Exit fullscreen mode

February 2026 has 28 days, so "Feb 31" overflows into March 3. If you need "end of next month" behavior, clamp the day explicitly or use a date library that handles it.

To sanity-check your results, a date calculator lets you add or subtract days, weeks and months and compare the output with your code. For leap years, week numbers and days in a month, the calendar and date reference tools are handy.

6. Off-by-one date differences

Are you counting the start date, the end date, or both? "How many days between Monday and Friday?" can reasonably be 4 or 5.

A reliable way to diff calendar dates in JavaScript is to normalize to UTC midnight first:

const MS_PER_DAY = 86_400_000;

function daysBetween(a, b) {
  const utcA = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
  const utcB = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
  return Math.round((utcB - utcA) / MS_PER_DAY);
}
Enter fullscreen mode Exit fullscreen mode

This avoids DST shifting the result by an hour and breaking a naive division. For business logic like SLAs, invoices and delivery windows, you often need working days instead, and business day tools and public holiday tools help you verify expected results.

7. Forgetting that the date changes across time zones

The same instant can be two different calendar dates in two places. This breaks things like daily reports, "created today" filters and birthday reminders.

const instant = new Date("2026-09-30T19:47:00Z");

const fmt = (tz) =>
  new Intl.DateTimeFormat("en-US", {
    timeZone: tz,
    dateStyle: "medium",
    timeStyle: "short",
  }).format(instant);

console.log(fmt("America/New_York")); // Sep 30, 2026, 3:47 PM
console.log(fmt("Asia/Dhaka"));       // Oct 1, 2026, 1:47 AM
Enter fullscreen mode Exit fullscreen mode

Same moment, different day. If your feature depends on "today," decide whose today it is: the server's, the user's or the business's.

A quick debugging checklist

  1. Is the value in UTC, local time or unknown?
  2. Does the string include an offset?
  3. Seconds or milliseconds?
  4. Are you doing elapsed-time math or calendar math?
  5. Does DST apply in this date range?
  6. Whose "today" are we using?

Free tools for quick checks

When something looks off, I like to verify with an independent tool before touching the code. The Noloii Time, Date & Calendar Tools collection is free and runs in the browser. The ones I reach for most as a dev:

What's the nastiest date bug you've ever tracked down? Share it in the comments.

Top comments (0)