I Built a Unix Timestamp Converter and Stepped on 3 JavaScript Date API Landmines

Published: (March 8, 2026 at 05:23 AM EDT)
3 min read
Source: Dev.to

Source: Dev.to

Overview

An API response returns 1709654400.

Can you tell what date that is at a glance? I couldn’t. Every time I needed to convert a Unix timestamp I’d Google “Unix Timestamp converter” and paste it into an online tool. That tiny friction adds up, so I built a zero‑click converter that runs directly in the browser.

While building it I ran into three common pitfalls in JavaScript’s Date API.

Landmine 1: new Date(1709654400) Returns 1970

The problem

const date = new Date(1709654400);
console.log(date.toISOString());
// => "1970-01-20T21:34:14.400Z"

JavaScript’s Date constructor expects milliseconds, but Unix timestamps are in seconds, so the result is off by a factor of 1,000.

The fix

const date = new Date(1709654400 * 1000);
console.log(date.toISOString());
// => "2024-03-05T00:00:00.000Z"

To make the UI forgiving we can auto‑detect the unit by digit count:

function toMillis(input) {
  if (/^\d{10}$/.test(input)) return Number(input) * 1000; // seconds
  if (/^\d{13}$/.test(input)) return Number(input);      // milliseconds
  return NaN;
}

Landmine 2: Hyphens and Slashes Parse Differently

The problem

console.log(new Date('2024-03-05').toISOString());
// => "2024-03-05T00:00:00.000Z" (interpreted as UTC)

console.log(new Date('2024/03/05').toISOString());
// => "2024-03-04T15:00:00.000Z" (interpreted as local time, e.g., JST)

Hyphens produce an ISO‑8601 string that is parsed as UTC, while slashes trigger a locale‑dependent parse that treats the input as local time. MDN warns that parsing non‑ISO‑8601 strings with the Date constructor is strongly discouraged because of these inconsistencies.

The fix

Only accept ISO‑8601‑compatible strings (e.g., YYYY‑MM‑DD) or manually split the components and construct the date with Date.UTC:

function parseISODate(str) {
  const [year, month, day] = str.split('-').map(Number);
  return new Date(Date.UTC(year, month - 1, day));
}

Landmine 3: The Timezone Display Maze

The problem

const offset = new Date().getTimezoneOffset();
console.log(offset); // e.g., JST: -540

getTimezoneOffset() returns the offset in minutes from UTC, with the sign inverted (JST +9 h → ‑540 min). It also only reports the user’s local timezone, so you can’t display arbitrary zones.

The fix – Intl.DateTimeFormat

const date = new Date('2024-03-05T10:00:00Z');
const formatted = date.toLocaleString('en-US', {
  timeZone: 'Asia/Tokyo',
  hour12: false,
  year: 'numeric',
  month: '2-digit',
  day: '2-digit',
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit'
});
console.log(formatted); // "03/05/2024, 19:00:00"

By supplying an IANA timezone identifier to the timeZone option, you can render the same instant in any region without external libraries. The app uses this to show a 10‑city comparison table (UTC, JST, EST, PST, CET, GMT, IST, CST, AEST, BRT).

Before / After

FeatureBeforeAfter
Checking timestampsGoogle → copy‑paste to an online toolOpen a browser tab; auto‑read from clipboard
Seconds vs. millisecondsCount digits manuallyAuto‑detect; no mental math
Date string parsingTrust new Date() → inconsistent resultsAccept only ISO‑8601 or parse manually
TimezonesConfused by getTimezoneOffset() signUse Intl.DateTimeFormat with IANA identifiers

All three landmines are “obvious once you know” them, but they can waste hours if you’re unaware. I hope this saves you some time.

Try the converter:

References

0 views
Back to Blog

Related posts

Read more »