← Back to blog

Parse Unix Timestamps: Fix Seconds vs Milliseconds for Developers

October 3, 2026
Parse Unix Timestamps: Fix Seconds vs Milliseconds for Developers

To parse a seconds-based Unix timestamp in JavaScript, multiply it by 1,000 and pass it to the Date constructor: new Date(unixSeconds * 1000). From there, use toISOString() when you need a stable, machine-readable output for logs or APIs, and toLocaleString() or Intl.DateTimeFormat when you are displaying the date to a person.


TL;DR:

  • Most Unix timestamps from APIs or logs are in seconds, so multiply by 1,000 to create a JavaScript Date object unless the timestamp is already in milliseconds.
  • Use toISOString() for machine-readable, fixed UTC output, and toLocaleString() or Intl.DateTimeFormat for user-facing date display that respects locale and timezone differences.
  • Always validate timestamp inputs with Number.isFinite() and check date.getTime() for NaN to prevent issues with invalid or negative timestamps.
  • When formatting dates, prefer explicit time zone settings with Intl.DateTimeFormat to avoid discrepancies caused by local environment variations.
  • Confirm your timestamp conversions using tools like Pingfloat's Unix Timestamp & Epoch Converter to ensure correct assumptions about units and edge cases before deployment.

Pingfloat
Verify Timestamp Assumptions Easily
Use Pingfloat’s timestamp tools to check Unix time conversions, units, and edge cases before deploying developer code.
Check timestamp conversions

Table of Contents

Quick examples for parsing and extracting timestamp parts

Most Unix timestamps you will see in APIs, databases, or log files are given in seconds since January 1, 1970. JavaScript's Date object, however, always expects milliseconds, which is the root of a common bug. Here is the baseline conversion:

const unixSeconds = 1718000000;
const date = new Date(unixSeconds * 1000);
console.log(date.toISOString()); // 2024-06-10T05:33:20.000Z

If your timestamp is already in milliseconds, skip the multiplication entirely:

const unixMilliseconds = 1718000000000;
const date = new Date(unixMilliseconds);
console.log(date.toISOString());

Once you have a Date object, pulling out individual parts is straightforward with the built-in getters. According to the MDN Date reference, these methods return local-time values unless you use their UTC equivalents.

  • date.getFullYear() returns the four-digit year.
  • date.getMonth() returns 0 for January through 11 for December, so add 1 for human-readable output.
  • date.getDate() returns the day of the month.
  • date.getHours(), date.getMinutes(), and date.getSeconds() return the time components.

Single-digit values need zero-padding for display. You can use String(value).padStart(2, '0') for each component, or take a shortcut with toISOString().slice(0, 10) to grab just the date portion in YYYY-MM-DD format. That slice trick is fast, but it only works in UTC, so it will shift the date for users in timezones ahead of or behind UTC at midnight.

For a quick time-only string, date.toISOString().slice(11, 19) gives you HH:MM:SS, again in UTC. These one-liners are convenient for debugging but should not replace proper formatting (covered below) once the output reaches end users.

How to validate timestamp inputs and handle edge cases

Unix timestamps arrive from APIs, user input, and third-party integrations, which means they are not always clean. Before trusting a value, check that it is actually a usable number and that the resulting date makes sense.

  • Confirm the input is numeric with Number.isFinite(Number(value)) before doing any math on it, a pattern recommended in freeCodeCamp's date validation guide.
  • After building the Date, check Number.isNaN(date.getTime()) to catch an Invalid Date rather than assuming the conversion worked.
  • Write a small normalization function that accepts an explicit unit parameter ('s' or 'ms') rather than guessing.
  • Treat the common 10-digit-versus-13-digit heuristic as a hint, not proof: a documented contract beats guesswork, as the Dev points out.

Negative timestamps are valid and simply represent instants before 1970. JavaScript's Date supports them within its supported numeric range, which spans roughly plus or minus 8.64e15 milliseconds from the epoch according to MDN. Leap seconds are ignored throughout that range.

Pro Tip: Never pass a raw numeric Unix timestamp into Date.parse(); that method is built for date-time strings, and feeding it raw numbers produces unreliable results.

Formatting choices: ISO strings, locale strings, and UTC getters

Once a timestamp is parsed, the next decision is how to present it, and that depends entirely on who or what is reading it. For machine-to-machine communication, logs, and API payloads, toISOString() is the safer choice because it always returns UTC in a fixed format, as MDN's Date documentation confirms.

const date = new Date(unixSeconds * 1000);
console.log(date.toISOString()); // "2024-06-10T05:33:20.000Z"

For human-facing display, toLocaleString() adapts to the user's system locale and timezone automatically, though that also means its output varies by environment:

console.log(date.toLocaleString()); // format depends on locale and timezone

When you need to read specific components without converting timezones, use the getUTC* family of getters (getUTCHours(), getUTCDate(), and so on) instead of their local equivalents. The table below summarizes when each formatting approach fits.

MethodOutput typeBest used for
toISOString()Fixed UTC stringLogs, APIs, database storage
toLocaleString()Locale-dependent stringQuick human display, non-critical UI
Intl.DateTimeFormatConfigurable, locale and timezone awareUser-facing dates needing a fixed timezone
getUTC* gettersIndividual UTC componentsCustom formatting logic in UTC
get* gettersIndividual local componentsCustom formatting in the server or browser's local time
  • Reach for toISOString() whenever the output needs to be identical regardless of where the code runs.
  • Reach for Intl.DateTimeFormat with an explicit timeZone whenever the audience is in a specific, known region rather than wherever the code happens to execute.

Practical Intl.DateTimeFormat examples for locale and time zones

Intl.DateTimeFormat solves the biggest weakness of toLocaleString(): it lets you pin down a timezone explicitly instead of relying on whatever the browser or server happens to be set to. The guide on managing timezones in JavaScript recommends this pattern for any date shown to a specific audience.

const date = new Date(unixSeconds * 1000);

new Intl.DateTimeFormat('en-US', {
  dateStyle: 'medium',
  timeStyle: 'long',
  timeZone: 'UTC'
}).format(date);

Swap timeZone: 'UTC' for an IANA zone name like 'America/New_York' or 'Europe/Paris' to show the same instant as it would appear in those regions. Pingfloat's own Time Zone Converter is handy for previewing how a single instant looks across several zones at once.

  • Add hour12: false to force 24-hour time, or hour12: true for a 12-hour clock with AM/PM.
  • Remember that output formatting, including locale defaults and available timezone names, can differ slightly between Node.js and browser runtimes depending on their built-in ICU data.

Checklist: best practices and common pitfalls to avoid

A few recurring mistakes cause most timestamp bugs in production, and most are easy to catch with a short review checklist.

  1. Decide upfront whether a given value is for machines or humans, and standardize that choice across the codebase.
  2. Document the timestamp unit (seconds or milliseconds) and the timezone assumption at every API boundary.
  3. Test conversions against epoch zero, a negative timestamp, a daylight saving transition, and a far-future date.
  4. Log toISOString() output on the server for debugging, and reserve localized strings for the client-side display layer.

Pro Tip: Keep one small file of known timestamp test cases, including a DST boundary and a pre-1970 value, and run it before every release that touches date logic.

Why explicit timestamp contracts save you debugging time

Why explicit timestamp contracts save you debugging time — overview diagram

The bugs I see most often in timestamp code are not math errors. They are assumptions: a function that silently expects milliseconds, or a display string that quietly picked up the server's timezone instead of the user's. Writing down the unit and timezone contract at each boundary costs a sentence in a comment or a type definition, and it prevents hours of confused debugging later.

Before merging anything that touches dates, I run a handful of cases through a converter by hand, including a negative timestamp and a value near a DST transition, which is also where DST-related data errors tend to surface in time-series work. Timestamp tools available online are convenient for that kind of manual sanity check during development.

— Andreas

Verify your conversions with Pingfloat's timestamp tools

Writing the conversion code is only half the job. Checking that it actually produces the right instant, in the right unit, across the edge cases that matter, is the part that catches bugs before a reviewer does. Pingfloat's Unix Timestamp & Epoch Converter lets you paste a raw value and instantly see it as ISO 8601, local time, and other common formats side by side, with no installation or account required.

Pingfloat

Use it to confirm seconds-versus-milliseconds assumptions, check a negative timestamp, or switch the displayed timezone before you commit formatting logic to a pull request. If your project needs ongoing checks beyond a one-off conversion, such as confirming an API's uptime or verifying an SSL certificate on the server returning those timestamps, Pingfloat's Website Uptime Monitor and SSL Checker cover that from the same site.

Sources

FAQ

How do I get the current Unix timestamp in JavaScript?

Use Math.floor(Date.now() / 1000), since Date.now() returns the current time in milliseconds according to MDN. Dividing by 1,000 and flooring the result converts it to whole Unix seconds.

How can I tell if a timestamp is in seconds or milliseconds?

Digit count is a common hint: 10-digit numbers are usually seconds and 13-digit numbers are usually milliseconds, but this is only a heuristic according to this timestamp conversion guide. The reliable fix is an explicit unit field or documented contract at the API boundary rather than guessing from the number's length.

How do I get the date that is 30 days ago in JavaScript?

Create a new Date, then subtract a month's worth of milliseconds, or use setDate(date.getDate() - 30) to let JavaScript handle month and year rollovers automatically. Both approaches return a valid Date object you can format with toISOString() or Intl.DateTimeFormat.

What does Date() do in JavaScript?

Called without new, Date() returns a string representing the current date and time, and it ignores any arguments passed to it. Called with new Date(milliseconds), it constructs a Date object representing the instant that many milliseconds after the Unix epoch.

How do I read a Unix timestamp correctly?

Multiply a seconds-based timestamp by 1,000 and pass it to new Date(), then read it with toISOString() for a fixed UTC string or Intl.DateTimeFormat for a timezone-specific display. Always validate the result with Number.isNaN(date.getTime()) before trusting it, as recommended in freeCodeCamp's validation guide.