DEV Community

Cover image for Why Date and Time Bugs Happen in JavaScript (And How Apps Actually Get It Right)
nishchal singh
nishchal singh

Posted on

Why Date and Time Bugs Happen in JavaScript (And How Apps Actually Get It Right)

If you’ve ever seen reminders fire early, late, or on the wrong day,

this post is for you.

I used to think date and time bugs were just edge cases.

They’re not.

Most of the time, they come from a slightly wrong mental model of how
time actually works in JavaScript. The problem only becomes visible
when an app starts dealing with real users, real schedules, and real
expectations.

This post explains why these bugs happen so often, how JavaScript really
handles date and time, and how production apps avoid them.

No heavy theory.
No library comparisons.
Just the parts that matter.


The illusion: “I used Date(), so time should be correct”

Most developers start with this:

new Date()
Enter fullscreen mode Exit fullscreen mode

It prints a date and time that looks correct, so we assume everything
underneath is local and intuitive.

That assumption is where many bugs begin.

JavaScript dates are not stored as local time.

Internally, they are stored as:

Milliseconds since January 1, 1970 (UTC)

Local time, timezone, and formatting are applied only when the date is
read or displayed.

This sounds like a small detail.
In real apps, it isn’t.


What JavaScript is actually doing

A useful mental model is this:

  • JavaScript stores one number
  • That number represents a moment in UTC
  • Local time is calculated only at display or formatting time

For example:

new Date("2026-02-10T09:00:00")
Enter fullscreen mode Exit fullscreen mode

This does not mean “9am in my timezone”.

It means “9am UTC, converted to the user’s local timezone”.

If your app does not control that context explicitly, time slowly drifts.


The three most common time mistakes

The three most common time mistakes in JavaScript

1. Assuming Date() is local internally

Date behaves like a local clock, but it is not one.

It is a UTC timestamp with a local view layered on top.

This becomes a problem when:

  • users are in different timezones
  • servers run in UTC
  • background jobs don’t share locale information

2. Mixing server time and client time

A very common pattern:

  • server schedules something
  • client displays or adjusts it
  • background job runs later

If these layers don’t agree on what “now” means, reminders drift.

This is especially dangerous for:

  • recurring schedules
  • weekly reminders
  • “tomorrow at 9am” logic

3. Generating dates without context

Any logic that generates dates needs to know:

  • today’s date
  • the user’s timezone
  • daylight saving rules

Without this context, it’s easy to generate reminders:

  • in the past
  • on the wrong day
  • in the wrong year

Why this gets worse in PWAs

These problems become much more visible in Progressive Web Apps.

Browsers are not designed to guarantee precise scheduling.
They optimize for:

  • battery life
  • performance
  • security

As a result:

  • background execution is delayed
  • service workers wake unpredictably
  • scheduled logic runs in time windows, not exact moments

Why scheduling is unreliable in PWAs

I ran into this while building a productivity app where reminders and
check-ins were core features.

Notifications worked.
Nothing crashed.
But timing was unreliable.

I wrote about that experience here:

When Notifications Matter, PWAs Start to Show Their Limits

https://dev.to/nishchaldev/when-notifications-matter-pwas-start-to-show-their-limits-5ebl

That post explains where things broke.
This post explains why.


How mature apps avoid time bugs

How mature apps avoid time bugs

Once I looked at how established reminder apps work, a clear pattern
emerged.

One clear definition of “now”

There is exactly one source of truth for current time:

  • based on the device timezone
  • or an explicit user setting

No guessing.
No hidden defaults.


Store in UTC, schedule in local time

This is the most important rule.

  • Store timestamps in UTC
  • Convert to local time for display
  • Schedule alarms using local context

This avoids:

  • daylight saving bugs
  • timezone drift
  • unexpected early or late triggers

Let the OS handle scheduling

On native platforms, reminders are scheduled using system services.

The operating system:

  • reschedules after reboots
  • adjusts for timezone changes
  • guarantees delivery timing

JavaScript logic does not need to stay alive.


The shift that fixed my app

After understanding these patterns, I changed the architecture:

  • the web app handles dashboards and planning
  • the native layer handles scheduling and notifications
  • the backend stores everything in UTC
  • time context is always explicit

The same product logic runs everywhere, but time-sensitive
responsibilities live where they belong.

The app is still evolving, but the difference is noticeable.

Live app:

https://wio-dev.vercel.app


A simple rule that helps

If you remember only one thing, remember this:

Time is not a utility. It’s a product feature.

If your app depends on time being correct:

  • model it deliberately
  • pass context explicitly
  • let the platform handle scheduling

Closing thought

JavaScript dates are not broken.
Browsers are not broken.

Most time bugs come from assumptions that feel reasonable until real
users and real schedules expose them.

Once your mental model matches how time actually works, things become
much simpler.


A question for you

  • Have you run into confusing date or timezone bugs?
  • How are you handling reminders or schedules today?
  • Did this explanation match what you’ve seen in practice?

I’d genuinely love to hear how others are dealing with this.

Top comments (0)