Skip to main content

Command Palette

Search for a command to run...

Displaying Date and Time Correctly in Frontend Applications (JavaScript)

Published
5 min read

Date and time handling in frontend applications is deceptively complex. Many bugs appear not because developers misunderstand JavaScript, but because they misunderstand time itself — timezones, locales, browser behavior, and operating system settings.

This article explains how date and time work in frontend applications, where the behavior comes from, and how to display them correctly using JavaScript.


1. Where Date and Time Actually Come From

Before touching code, it’s important to understand who is responsible for what.

1. JavaScript Engine (Language Level)

  • Provides the Date object

  • Stores time internally as milliseconds since Unix Epoch (UTC)

  • Does not know about formatting rules or human languages

2. Browser APIs

  • Provide Intl.* APIs (internationalization)

  • Access timezone and locale information

  • Format dates for humans

3. User’s System (OS & Browser Settings)

  • System timezone (e.g. UTC+1)

  • System locale (e.g. en-US, nb-NO)

  • Daylight Saving Time rules

👉 Your frontend code sits on top of all three layers.


2. What Is UTC and Why It Matters

What is UTC?

UTC (Coordinated Universal Time) is the global reference time standard.

  • It does not change with seasons

  • It does not depend on geography

  • It is not affected by daylight saving

All timezones are defined as offsets from UTC:

  • Norway: UTC+1 (UTC+2 in summer)

  • India: UTC+5:30

  • New York: UTC-5 (UTC-4 in summer)

Why frontend apps should use UTC

If every system used its own local time:

  • Data would become ambiguous

  • “Same moment” would mean different times

  • Bugs would appear when users change location

Rule:

Store and exchange time in UTC. Convert only for display.


3. How JavaScript Stores Time Internally

When you create a Date object:

const now = new Date();

Internally, JavaScript stores:

Milliseconds since 1970-01-01T00:00:00 UTC

This means:

  • JavaScript always stores time in UTC

  • Timezone conversion happens only when displaying

This behavior comes from the JavaScript engine, not the browser UI.


4. How to Generate Date & Time in UTC

Current UTC time

const nowUtc = new Date();

Even though this looks local, internally it is UTC.

Explicit UTC timestamp

const utcDate = new Date(Date.UTC(2025, 11, 25, 22, 30));

⚠️ Month is zero-based (11 = December).

Backend → Frontend best practice

Backend sends:

"2025-12-25T22:30:00Z"

Frontend parses:

const date = new Date("2025-12-25T22:30:00Z");

5. What Is ISO 8601 and Why JavaScript Loves It

What is ISO 8601?

ISO 8601 is an international standard for date-time strings.

Example:

2025-12-25T22:30:00Z

Meaning:

  • YYYY-MM-DD → date

  • T → separator

  • HH:mm:ss → time

  • Z → UTC timezone

Why you should always use ISO format

JavaScript guarantees correct parsing only for ISO 8601.

new Date("2025-12-25T22:30:00Z"); // ✅ Safe
new Date("25/12/2025");          // ❌ Locale dependent

ISO parsing logic comes from the JavaScript specification, not the browser UI.


6. Why toString() and toLocaleString() Are Not Enough

date.toString();

Problems:

  • Unpredictable format

  • Hard to read

  • Not user-friendly

  • Changes between browsers

Even:

date.toLocaleString();

Is:

  • Implicit

  • Hard to control

  • Not consistent across products

We need explicit formatting.


7. What Is Intl.DateTimeFormat?

Intl.DateTimeFormat is part of the Browser Internationalization API.

It:

  • Uses browser + OS locale data

  • Applies correct language, calendar, and formatting rules

  • Handles daylight saving automatically

Basic usage

const formatter = new Intl.DateTimeFormat("en-US", {
  dateStyle: "medium",
  timeStyle: "short"
});

formatter.format(date);

Why this is the correct solution

  • No manual formatting

  • Accessibility-friendly

  • Future-proof

  • Locale-aware

👉 This formatting logic comes from the browser, backed by OS locale data, not JavaScript alone.


8. What Is a Locale?

A locale defines:

  • Language

  • Date format

  • Number format

  • Calendar rules

Examples:

  • en-US → December 26, 2025

  • en-GB → 26 December 2025

  • nb-NO → 26. desember 2025

Why locale matters

Hardcoding formats assumes:

  • One country

  • One language

  • One culture

Which breaks global applications.


9. How Locale Is Determined Automatically

navigator.language

This value comes from:

  1. Browser settings

  2. OS language preferences

  3. User selection

Automatic formatting

new Intl.DateTimeFormat(navigator.language, {
  dateStyle: "long"
}).format(date);

You do nothing, yet users see dates formatted correctly.


10. Why Being Timezone Explicit Matters

By default:

Intl.DateTimeFormat().format(date);

Uses:

  • User’s system timezone

But sometimes you must override it

Example: Logs in UTC

new Intl.DateTimeFormat("en-GB", {
  timeZone: "UTC",
  dateStyle: "medium",
  timeStyle: "short"
}).format(date);

Example: Business timezone

timeZone: "America/New_York"

Why this helps

  • Removes ambiguity

  • Aligns all users to same reference

  • Critical for finance, bookings, audits

Timezone data comes from the browser’s timezone database, which itself is updated by the OS/browser.


11. Relative Time and Human-Friendly UI

Using browser API:

new Intl.RelativeTimeFormat("en", { numeric: "auto" })
  .format(-5, "minute");

Output:

“5 minutes ago”

This:

  • Respects language

  • Handles pluralization

  • Uses browser localization rules


12. Summary: Who Does What?

ResponsibilitySource
Time storageJavaScript engine
UTC handlingJavaScript spec
LocalizationBrowser Intl API
Timezone rulesOS + browser
Language rulesUser system

Final Takeaway

JavaScript stores time in UTC.
Browsers translate time into human language.
User systems decide how it looks.

Correct frontend date handling means:

  • Use UTC everywhere internally

  • Exchange ISO 8601 strings

  • Format with Intl

  • Respect locale automatically

  • Be explicit about timezone when needed

Do this, and your app will behave correctly for every user, everywhere.