I Built a Unix Timestamp Converter and Stepped on 3 JavaScript Date API Landmines
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
| Feature | Before | After |
|---|---|---|
| Checking timestamps | Google → copy‑paste to an online tool | Open a browser tab; auto‑read from clipboard |
| Seconds vs. milliseconds | Count digits manually | Auto‑detect; no mental math |
| Date string parsing | Trust new Date() → inconsistent results | Accept only ISO‑8601 or parse manually |
| Timezones | Confused by getTimezoneOffset() sign | Use 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: