Skip to content
Nicolas Chiong· 4 min read

A Node 26 Temporal playbook for date math

Node 26 enables Temporal by default, which makes date logic safer if teams separate instants, calendar dates, and time-zone-aware values.

Node 26 makes Temporal available by default, and that changes how I would write new date logic in backend JavaScript. I would not rip out every Date call in a working system. I would stop adding new date bugs in the places where time zones, billing periods, schedules, and user-facing calendars matter.

The production rule

The rule is simple: choose the Temporal type that matches the business fact.

Business factTemporal type
A database timestampTemporal.Instant
A birthday or invoice dateTemporal.PlainDate
A local meeting time without a zone yetTemporal.PlainDateTime
A scheduled event in a known zoneTemporal.ZonedDateTime
A duration between valuesTemporal.Duration

That table prevents most of the confusion. A timestamp is not a calendar date. A calendar date is not a moment in UTC. A recurring local time is not the same thing as adding 24 hours forever.

The old Date API made those distinctions too easy to blur. MDN's Temporal docs call out the core problem: Date mixes timestamp behavior with local component behavior, and it only really gives you UTC or the device's local zone. That is fine for some logging and painful for products that users experience through calendars.

Start at the boundary

I would introduce Temporal at boundaries first. Parse incoming API values into explicit types, do date math with those types, then serialize back to the storage format the rest of the system already expects.

function nextBillingDate({ currentDate, months }) {
  return Temporal.PlainDate.from(currentDate).add({ months }).toString();
}

console.assert(
  nextBillingDate({ currentDate: "2026-01-31", months: 1 }) === "2026-02-28"
);

That example is intentionally small. Billing date math is calendar math, so PlainDate is the right tool. I do not want a hidden local timezone conversion deciding whether the user gets charged on the wrong day.

For event scheduling, I would use ZonedDateTime and require a named IANA zone such as Asia/Manila or America/New_York, not a bare offset. MDN's ZonedDateTime docs are blunt about why: offsets miss daylight-saving and political time-zone changes. A named zone gives future calculations the data needed to stay aligned with local wall-clock time.

What not to migrate first

Do not start with logging. Logs are already instants. A stable ISO timestamp from the platform is usually fine, and a broad logging rewrite creates risk without much product value.

Do not start with every date library import either. Some libraries are doing formatting, locale handling, or compatibility work you still need. The practical first targets are smaller:

  1. Billing periods.
  2. Trial expiration dates.
  3. Subscription renewal windows.
  4. Booking and appointment times.
  5. Calendar reminders.
  6. SLA deadlines shown to users.

These are the places where a one-hour daylight-saving jump or a date parsed in the wrong zone turns into a support ticket.

Node 26 is current, not the default production baseline

Node's release page lists Node 26 as Current, with Node 24 and Node 22 still in LTS lines as of July 2026. That matters for rollout. I would test Temporal in Node 26 now, but I would not move a conservative production fleet to Current just to get one API.

The better path is to design the date model now and ship it where the runtime supports it. If the application must stay on LTS, use a deliberately scoped compatibility path and remove it when the fleet moves. Keep that compatibility wrapper small. The goal is not a company-wide time abstraction. The goal is to stop passing ambiguous strings through the core workflow.

This is the same reasoning I used in my Node.js permission model field guide: a runtime feature is only useful when it lands behind a narrow operating rule. For permissions, that rule was least privilege around file and network access. For Temporal, it is type the time concept before doing math.

A review checklist

When I review a Temporal change, I ask five questions:

  1. Does the code use Instant for machine time and PlainDate for calendar-only values?
  2. Does user-facing scheduling store or receive a named time zone?
  3. Does the code avoid adding fixed hours when the product means calendar days?
  4. Does serialization happen at the boundary instead of halfway through the workflow?
  5. Is there one test covering month-end, daylight-saving, or zone conversion behavior?

If the answer to those questions is yes, the change is probably useful. If the answer is no, Temporal can still be misused. A sharper API does not replace product thinking.

The takeaway

Temporal is not a reason to churn a codebase. It is a reason to stop treating every time value as the same kind of string. The forward-looking move is to classify date facts at the edge of the system, migrate the workflows where calendar bugs hurt users, and let boring timestamp code stay boring until it has a real reason to change.

nodejsjavascripttemporalbackend

References

  1. nodejs.orgNode.js
  2. nodejs.orgNode.js
  3. developer.mozilla.orgMDN
  4. developer.mozilla.orgMDN
  5. github.comTC39

Related writing

← PreviousAn npm trusted publishing migration playbook

Let's make something useful.

Start a conversation