Command Palette

Search for a command to run...

Blog
Next

Don't Let Server Time Decide Your Business Logic

Date.now() and getHours() are fine for the current moment — until machine local time quietly becomes business logic on a server, worker, or browser in another timezone.

It is easy to write code like this:

const now = Date.now();

or:

const date = new Date();
 
date.getHours();
date.getDate();
date.getMonth();

Most of the time, there is nothing wrong with using Date like this.

The problem starts when the result is used for business logic without considering the timezone of the machine running the code.

Date.now() Is Not Local Server Time

Date.now() returns the current moment as a number of milliseconds since the Unix epoch.

It does not return:

10:30 AM India

or:

10:30 AM New York

It represents the same instant regardless of where the server is running.

For example:

Date.now();

is safe when the requirement is simply:

"What is the current moment?"

The problem appears when that moment is converted into a local date or time using the machine's timezone.

const date = new Date();
 
date.getHours();
date.getDate();
date.getMonth();

These methods use the local timezone of the environment running the code.

So the same instant can produce different local values on different machines.

Server A → Asia/Kolkata
Server B → America/New_York

The instant is the same, but:

date.getHours();

can return different values.

When Machine Time Becomes a Problem

This becomes important when local time is used to make a business decision.

For example:

if (new Date().getHours() === 10) {
  // run something
}

This code doesn't really mean:

"Run this at 10 AM for the business."

It means:

"Run this when the machine's local clock says 10 AM."

If the same application moves to another region, the behavior can change without any business configuration changing.

The same problem can appear with:

new Date().getDate();
new Date().getMonth();
new Date().getDay();

If the code is deciding things like:

  • which business day it is
  • whether something is due today
  • whether a schedule should run
  • when a daily process should start
  • which date should be shown

then relying on the machine's timezone can create unexpected behavior.

Servers and Workers Can Have Different Environments

This becomes easier to miss when the application has multiple processes.

For example:

API Server
    ↓
Queue
    ↓
Worker

The API and worker may run on different machines, containers, or regions.

If business logic depends on:

new Date().getHours();

the result can depend on where that particular process is running.

The problem isn't that the server has a timezone.

The problem is that the application silently uses that timezone as part of its business logic.

Use an Explicit Timezone When Local Time Matters

If the requirement is based on a particular timezone, make that timezone explicit.

For example:

const timeZone = "America/New_York";
 
const localTime = new Intl.DateTimeFormat("en-US", {
  timeZone,
  dateStyle: "medium",
  timeStyle: "short",
}).format(new Date());

Now the result doesn't depend on the timezone configured on the server.

The same idea applies on the frontend.

If the requirement is to show the user's local time, the browser's timezone can be used.

If the requirement is to show a business's local time, use the timezone configured for that business.

The important part is knowing which clock the operation belongs to.

Scheduling

Scheduling is where this distinction becomes more important.

Suppose a user selects:

Date: 2026-03-10
Time: 10:00 AM
Timezone: America/New_York

Send those values to the backend:

createSchedule({
  date: "2026-03-10",
  time: "10:00",
  timeZone: "America/New_York",
});

The backend can interpret that local date and time using the supplied timezone and convert it into an exact moment.

Date + Time + Timezone
          ↓
       Backend
          ↓
      UTC timestamp
          ↓
        Queue
          ↓
        Worker

The worker does not need to recalculate New York time.

It only needs to execute the job at the scheduled moment.

Delayed Jobs

For a delayed job, the delay should be based on the target moment.

Conceptually:

Target moment - Current moment
             ↓
         Delay
             ↓
           Queue
             ↓
          Worker

The worker's local timezone should not determine whether the job is due.

This is why code that derives business decisions from:

new Date().getHours();

inside a worker can be risky.

Recurring Schedules Are Different

There is an important difference between:

Every day at 10:00 AM

and:

Every 24 hours

The first is based on a local clock.

The second is a duration.

For a recurring schedule such as:

Every day at 10:00 AM
America/New_York

the next occurrence needs to be calculated using that timezone.

After calculating the next occurrence, the system can turn it into an exact moment and pass that to the queue.

Recurring rule
      ↓
Calculate next occurrence
      ↓
Exact moment
      ↓
Queue
      ↓
Worker

The timezone information also allows the backend to apply rules such as daylight saving time when calculating the time.

A Simple Rule

A useful way to think about it is:

Date.now()
→ current moment
 
UTC timestamp
→ exact moment shared between systems
 
Timezone
→ converts an exact moment to local date/time
  or gives meaning to a local date/time
 
Machine timezone
→ should not silently define business behavior

The goal isn't to avoid Date.now() or new Date().

They are normal and useful APIs.

The goal is to avoid letting the timezone of a browser, server, container, or worker accidentally become part of the business logic.

When local time matters, make the timezone explicit.

When only an exact moment matters, work with the timestamp.

That small distinction prevents a lot of environment-dependent behavior.

“Build it. Break it. Understand it. Make it better.”

— Anmol Kumar