How to Convert Unix Timestamps in JavaScript — Complete Guide

Unix timestamps are everywhere in JavaScript development — API responses, JWT tokens, database records, log files. Handling them correctly, without timezone bugs or millisecond confusion, is a skill you'll use daily. This guide covers every conversion you'll ever need.

What is a Unix Timestamp?

A Unix timestamp is the number of seconds (or milliseconds) that have elapsed since January 1, 1970 at 00:00:00 UTC — the Unix epoch. It's timezone-agnostic and universally supported, which makes it the standard representation of time in APIs, databases, and distributed systems.

The current Unix timestamp is around 1,715,000,000 seconds. If you see a 10-digit number, it's Unix seconds. If you see a 13-digit number, it's Unix milliseconds.

💡

Quick check: paste any timestamp into UnixLi — it auto-detects seconds, milliseconds, microseconds, ISO 8601, RFC 2822 and converts them all instantly.

Unix Seconds vs Milliseconds — The Most Common Bug

This single confusion causes more timestamp bugs than anything else. JavaScript's Date API works internally in milliseconds, but most REST APIs, Unix system calls, and databases return timestamps in seconds.

JavaScript
// JavaScript always uses milliseconds internally
const nowMs  = Date.now();                         // 1715429912000 ← 13 digits
const nowSec = Math.floor(Date.now() / 1000);     // 1715429912    ← 10 digits

// Rule: 10 digits = seconds · 13 digits = milliseconds
⚠️

Classic mistake: new Date(1715429912) gives you a date in January 1970, because JavaScript interprets the number as milliseconds. You need new Date(1715429912 * 1000).

Convert Unix Timestamp to Date

The Date constructor accepts milliseconds. Always multiply Unix seconds by 1000.

JavaScript
// From Unix seconds (most APIs, databases)
const unixSeconds = 1715429912;
const date = new Date(unixSeconds * 1000); // ✅ multiply by 1000

// From Unix milliseconds (Date.now(), Java, JavaScript)
const unixMs = 1715429912000;
const date2 = new Date(unixMs); // ✅ no multiplication needed

// Verify: both give the same result
console.log(date.toISOString()); // → "2026-05-11T14:38:32.000Z"

Convert Date to Unix Timestamp

getTime() returns milliseconds. Divide by 1000 and floor for Unix seconds.

JavaScript
const date = new Date(); // or any Date object

// To Unix seconds
const unixSec = Math.floor(date.getTime() / 1000);

// To Unix milliseconds
const unixMs = date.getTime(); // or Date.now() for current time

// Reusable helper
const toUnix = (d) => Math.floor(d.getTime() / 1000);
const fromUnix = (ts) => new Date(ts * 1000);

Format Timestamps with Intl.DateTimeFormat

The native Intl.DateTimeFormat API is the modern, library-free way to format dates. It supports any locale and timezone.

JavaScript
const date = new Date(1715429912 * 1000);

// ISO 8601 — always UTC, timezone-safe
date.toISOString(); // → "2026-05-11T14:38:32.000Z"

// Full human-readable (UTC)
new Intl.DateTimeFormat('en-US', {
  dateStyle: 'full',
  timeStyle: 'long',
  timeZone: 'UTC',
}).format(date);
// → "Sunday, May 11, 2026 at 2:38:32 PM UTC"

// Custom format in a specific timezone
new Intl.DateTimeFormat('en-GB', {
  day: '2-digit', month: 'short', year: 'numeric',
  hour: '2-digit', minute: '2-digit',
  timeZone: 'Europe/Paris',
}).format(date);
// → "11 May 2026, 16:38"

// SQL-ready format (manual)
const toSQL = (d) => {
  const p = (n) => String(n).padStart(2, '0');
  return `${d.getUTCFullYear()}-${p(d.getUTCMonth()+1)}-${p(d.getUTCDate())} `
       + `${p(d.getUTCHours())}:${p(d.getUTCMinutes())}:${p(d.getUTCSeconds())}`;
};
toSQL(date); // → "2026-05-11 14:38:32"

Relative Time — "3 minutes ago"

The Intl.RelativeTimeFormat API handles relative time natively, with correct pluralization for any locale.

JavaScript
function timeAgo(unixSeconds) {
  const diff = unixSeconds - Math.floor(Date.now() / 1000); // negative = past
  const abs  = Math.abs(diff);
  const rtf  = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

  if (abs < 60)   return rtf.format(diff, 'second'); // "3 seconds ago"
  if (abs < 3600) return rtf.format(Math.round(diff/60), 'minute');
  if (abs < 86400)return rtf.format(Math.round(diff/3600), 'hour');
  return rtf.format(Math.round(diff/86400), 'day');
}

timeAgo(1715429912); // → "3 days ago" / "in 2 hours" depending on current time

Timezone Conversion

Unix timestamps are always UTC. Timezone conversion only happens at display time — and never store timestamps in local time.

JavaScript
const date = new Date(1715429912 * 1000);

// Display in any IANA timezone
const inTimezone = (date, tz) =>
  new Intl.DateTimeFormat('en-US', {
    timeZone: tz,
    dateStyle: 'medium',
    timeStyle: 'short',
  }).format(date);

inTimezone(date, 'America/New_York'); // → "May 11, 2026, 10:38 AM"
inTimezone(date, 'Asia/Tokyo');       // → "May 11, 2026, 11:38 PM"
inTimezone(date, 'Europe/Paris');     // → "May 11, 2026, 4:38 PM"

// Get the UTC offset as a string
const getOffset = (tz) =>
  new Intl.DateTimeFormat('en', { timeZone: tz, timeZoneName: 'shortOffset' })
    .formatToParts(new Date())
    .find(p => p.type === 'timeZoneName')?.value;

getOffset('America/New_York'); // → "GMT-4"
getOffset('Asia/Kolkata');     // → "GMT+5:30"

TypeScript: Branded Types to Prevent Bugs

TypeScript can enforce the distinction between seconds and milliseconds at compile time using branded types. This makes it impossible to accidentally pass milliseconds where seconds are expected.

TypeScript
// Branded types — same runtime value, different type identity
type UnixSeconds = number & { readonly _brand: 'UnixSeconds' };
type UnixMs      = number & { readonly _brand: 'UnixMs' };
type ISOString   = string & { readonly _brand: 'ISO' };

// Type-safe helpers
const toDate   = (t: UnixSeconds): Date        => new Date((t as number) * 1000);
const toUnix   = (d: Date): UnixSeconds        => Math.floor(d.getTime() / 1000) as UnixSeconds;
const toISO    = (t: UnixSeconds): ISOString   => new Date((t as number) * 1000).toISOString() as ISOString;

// Usage — TypeScript catches type mismatches at compile time
const now: UnixSeconds = toUnix(new Date());
const date = toDate(now);
const iso  = toISO(now);

// This would be a TypeScript error ✅
// toDate(Date.now() as UnixMs); ← Type 'UnixMs' is not assignable to 'UnixSeconds'

Common Mistakes to Avoid

  • Forgetting × 1000new Date(1715429912) gives January 1970. Always multiply Unix seconds by 1000.
  • Using new Date(string) without timezone info — "2026-05-11 14:38:32" parsed without timezone is browser-dependent. Use "2026-05-11T14:38:32Z" (with the Z for UTC).
  • Storing dates in local time — Always store timestamps as Unix seconds or UTC strings. Never as local time strings.
  • Assuming Date.now() returns seconds — It returns milliseconds. Use Math.floor(Date.now() / 1000) for seconds.
  • Using getHours() instead of getUTCHours() — The non-UTC methods depend on the server/browser timezone, causing unpredictable behavior across deployments.

Quick Reference

GoalJavaScript code
Current Unix secondsMath.floor(Date.now() / 1000)
Current Unix millisecondsDate.now()
Unix seconds → Datenew Date(ts * 1000)
Unix milliseconds → Datenew Date(ts)
Date → Unix secondsMath.floor(date.getTime() / 1000)
Date → ISO 8601date.toISOString()
Date → UTC stringdate.toUTCString()
Formatted (locale-aware)new Intl.DateTimeFormat(...).format(date)
Relative timenew Intl.RelativeTimeFormat(...).format(n, 'minute')

Try it instantly — no setup needed

Paste any timestamp and UnixLi converts it to all formats at once — Unix seconds, ISO 8601, SQL, RFC 2822, relative time, and generates the JavaScript code snippet automatically.

Open UnixLi — free, no signup →

Summary

The three rules to remember for timestamp handling in JavaScript:

  • 10 digits = seconds, 13 digits = milliseconds. Always multiply seconds by 1000 when passing to Date.
  • Store timestamps as Unix seconds or ISO 8601 UTC. Never as local time strings.
  • Use Intl.DateTimeFormat for formatting. It's native, locale-aware, and handles timezones correctly without any library.

For more timestamp guides, see the UnixLi blog — including upcoming articles on JWT expiration, Python datetime, and PostgreSQL timestamp handling.