Web Development

Unix Timestamp: Seconds vs Milliseconds

Understand the critical difference between Unix timestamps in seconds and milliseconds, why JavaScript uses milliseconds, and how to convert between formats correctly.

By Inventive HQ Team

To tell a Unix timestamp in seconds from one in milliseconds, count the digits: a present-day seconds value is about 10 digits (1735689600) and a milliseconds value is about 13 digits (1735689600000) — the same instant, just multiplied by 1,000. To convert, multiply seconds by 1,000 to get milliseconds, or divide milliseconds by 1,000 (and floor) to get seconds. Both count time since the Unix Epoch (January 1, 1970 UTC); they differ only by a factor of 1,000. The fast programmatic tell is magnitude: any value below ten billion (10,000,000,000) is seconds, anything at or above it is milliseconds — because ten billion seconds is the year 2286, so a normal modern date that big can only be milliseconds.

That's the summary an AI Overview would give you. The rest of this page is what it can't: a side-by-side table of which languages emit which format, an animated ruler that shows the 10-vs-13-digit relationship, the exact one-line conversions, and the specific bugs (dates in 1970, dates in the year 56970) that each mistake produces — plus a live converter that auto-detects the format for you.

Loading interactive tool...

Seconds vs milliseconds at a glance

The two formats represent the identical moment; the only question is the unit. This table is the whole decision in one place:

Seconds (Unix time)Milliseconds
Digit count (2001–2286)~10 digits~13 digits
Example — 2025-01-01 00:00 UTC17356896001735689600000
Magnitude tellvalue < 10,000,000,000value ≥ 10,000,000,000
Emitted byUnix date +%s, PostgreSQL extract(epoch …), MySQL UNIX_TIMESTAMP(), Python time.time(), PHP time(), Ruby .to_i, most back-end REST APIsJavaScript Date.now() / getTime(), Java System.currentTimeMillis(), Node.js, most browser & front-end timing
Precision1 second1 millisecond
Convert to the other× 1000 → milliseconds÷ 1000 (floor) → seconds
Range / overflow notesigned 32-bit seconds overflow on 2038-01-19 (the Y2038 problem); use 64-bit13 digits until year 2286; safe inside JS Number until year 285616

The mechanical relationship — seconds × 1,000 = milliseconds — is exactly why one format is three digits longer than the other. This ruler makes it visible:

Seconds versus milliseconds: digit length and the ×1000 / ÷1000 conversion A 10-digit seconds value converts to a 13-digit milliseconds value by multiplying by one thousand, which appends three zeros; dividing by one thousand reverses it. Same instant, two units — the extra three zeros are ×1000 SECONDS · 10 digits 1735689600 MILLISECONDS · 13 digits 1735689600000 + three zeros × 1000 ÷ 1000

The Critical Difference Between Seconds and Milliseconds

One of the most common sources of bugs in time-related code is the confusion between Unix timestamps measured in seconds versus milliseconds. While both represent time elapsed since the Unix Epoch (January 1, 1970 UTC), they differ by a factor of 1,000—and mixing them up can cause your dates to appear decades off or events to seem instantaneous.

Let's break down this crucial distinction and learn how to handle timestamp conversions correctly across different programming environments.

Need to check a timestamp's format or convert it? Try our free Unix Timestamp Converter to do this instantly—it auto-detects seconds vs milliseconds and shows the matching date.

Understanding the Two Formats

Unix Timestamp in Seconds (10 digits)

The traditional Unix timestamp format counts seconds since the epoch and typically contains 10 digits (as of 2025).

Example: 1735689600

This represents January 1, 2025, 00:00:00 UTC.

Where it's used:

  • Unix/Linux system time (date +%s)
  • PHP (time(), strtotime())
  • Python (time.time())
  • Ruby (Time.now.to_i)
  • Most SQL databases (UNIX_TIMESTAMP() in MySQL)
  • Server logs and system events
  • Most RESTful APIs (especially backend systems)

Unix Timestamp in Milliseconds (13 digits)

The milliseconds format counts milliseconds since the epoch and contains 13 digits.

Example: 1735689600000

This represents the exact same moment: January 1, 2025, 00:00:00 UTC.

Where it's used:

  • JavaScript (Date.now(), new Date().getTime())
  • Java (System.currentTimeMillis())
  • Node.js (inherits JavaScript behavior)
  • Some modern APIs that require sub-second precision
  • High-frequency trading systems
  • Performance monitoring and profiling

Why JavaScript Uses Milliseconds

JavaScript's decision to use milliseconds has historical roots. When Brendan Eich created JavaScript in 1995, he modeled the Date object after Java's java.util.Date class, which used milliseconds for finer precision.

This choice has both advantages and drawbacks:

Advantages of Milliseconds

Sub-second precision: Milliseconds allow you to measure events that happen faster than one second:

const start = Date.now(); // 1735689600000
// ... some operation ...
const end = Date.now();   // 1735689600123
const duration = end - start; // 123 milliseconds

Animation and timing: When building user interfaces, milliseconds matter:

// Request animation frame timing
function animate(timestamp) {
  // timestamp is in milliseconds
  const progress = (timestamp - animationStart) / 1000;
  // Convert to seconds for calculations
}

Event logging: Modern web analytics and performance monitoring need millisecond precision:

// Tracking page load performance
const pageLoadTime = performance.timing.loadEventEnd -
                     performance.timing.navigationStart;
Advertisement

The Compatibility Challenge

The millisecond format creates friction when JavaScript applications communicate with backend systems that use seconds:

// Frontend sends timestamp to backend
fetch('/api/save', {
  method: 'POST',
  body: JSON.stringify({
    timestamp: Date.now() // ❌ 1735689600000 (milliseconds)
  })
});

// Backend (PHP) receives it
$timestamp = $_POST['timestamp']; // 1735689600000
$date = date('Y-m-d', $timestamp); // ❌ Year 56970!

This is one of the most common bugs in web development.

Converting Between Seconds and Milliseconds

Milliseconds to Seconds

To convert from JavaScript milliseconds to Unix seconds:

// Method 1: Division with Math.floor
const seconds = Math.floor(Date.now() / 1000);

// Method 2: Integer division with bitwise OR (faster)
const seconds = (Date.now() / 1000) | 0;

// Method 3: Using Math.trunc (clearer intent)
const seconds = Math.trunc(Date.now() / 1000);

Important: Always use Math.floor() or integer conversion, not just division:

// ❌ WRONG: Creates decimal number
const seconds = Date.now() / 1000; // 1735689600.123

// ✅ CORRECT: Integer seconds
const seconds = Math.floor(Date.now() / 1000); // 1735689600

Seconds to Milliseconds

Converting seconds to milliseconds is simpler—just multiply by 1,000:

// Backend returns seconds
const secondsFromAPI = 1735689600;

// Convert to milliseconds for JavaScript Date
const date = new Date(secondsFromAPI * 1000);

console.log(date); // 2025-01-01T00:00:00.000Z

Detecting the Format Automatically

How can you tell if a timestamp is in seconds or milliseconds? Here's a reliable heuristic:

function detectTimestampFormat(timestamp) {
  // Count digits
  const digits = timestamp.toString().length;

  if (digits === 10) {
    return 'seconds';
  } else if (digits === 13) {
    return 'milliseconds';
  } else {
    throw new Error('Invalid timestamp format');
  }
}

// Or check against a known date
function isMilliseconds(timestamp) {
  // Anything after year 2286 as seconds would be
  // more than 10 trillion as milliseconds
  return timestamp > 10000000000;
}

Smart conversion function:

function toJavaScriptDate(timestamp) {
  // If it looks like seconds, convert to milliseconds
  if (timestamp < 10000000000) {
    return new Date(timestamp * 1000);
  }
  // Otherwise, assume milliseconds
  return new Date(timestamp);
}

Common Pitfalls and How to Avoid Them

Pitfall 1: Double Conversion

// Backend API returns seconds
const apiResponse = { created_at: 1735689600 };

// ❌ WRONG: Already in seconds, don't convert again
const date1 = new Date(apiResponse.created_at / 1000);
// Results in 1970-01-21

// ✅ CORRECT: Convert seconds to milliseconds
const date2 = new Date(apiResponse.created_at * 1000);
// Results in 2025-01-01

Pitfall 2: Forgetting to Convert

// Receiving Unix seconds from backend
const unixSeconds = 1735689600;

// ❌ WRONG: JavaScript Date expects milliseconds
const date = new Date(unixSeconds);
console.log(date); // 1970-01-21 (way off!)

// ✅ CORRECT: Multiply by 1000
const date = new Date(unixSeconds * 1000);
console.log(date); // 2025-01-01 (correct!)

Pitfall 3: Mixing Formats in Calculations

// ❌ WRONG: Mixing seconds and milliseconds
const serverTime = 1735689600; // seconds from API
const clientTime = Date.now();  // milliseconds
const diff = clientTime - serverTime; // meaningless number!

// ✅ CORRECT: Convert to same format first
const serverTimeMs = serverTime * 1000;
const diff = clientTime - serverTimeMs; // milliseconds difference

Pitfall 4: Database Timestamp Columns

When storing JavaScript timestamps in SQL databases:

// ❌ WRONG: Storing milliseconds where seconds expected
db.query(
  'INSERT INTO events (timestamp) VALUES (?)',
  [Date.now()] // 1735689600000
);

// ✅ CORRECT: Convert to seconds for database
db.query(
  'INSERT INTO events (timestamp) VALUES (?)',
  [Math.floor(Date.now() / 1000)] // 1735689600
);

Best Practices for Full-Stack Applications

1. Document Your API Clearly

In your API documentation, always specify the timestamp format:

/**
 * @api {post} /events Create Event
 * @apiParam {Number} timestamp Unix timestamp in SECONDS
 * @apiSuccess {Object} event Created event
 * @apiSuccess {Number} event.created_at Unix timestamp in SECONDS
 */

2. Use Consistent Format in APIs

Choose one format for your API and stick with it:

// ✅ GOOD: API always uses seconds
app.get('/api/events', (req, res) => {
  res.json({
    events: events.map(e => ({
      id: e.id,
      name: e.name,
      created_at: Math.floor(e.created_at / 1000) // Always seconds
    }))
  });
});

3. Create Conversion Utilities

Build reusable conversion functions:

// utils/time.js
export const toUnixSeconds = (date = new Date()) => {
  return Math.floor(date.getTime() / 1000);
};

export const fromUnixSeconds = (seconds) => {
  return new Date(seconds * 1000);
};

export const toUnixMilliseconds = (date = new Date()) => {
  return date.getTime();
};

export const fromUnixMilliseconds = (milliseconds) => {
  return new Date(milliseconds);
};

4. Validate Timestamp Format

Add validation to catch errors early:

function validateUnixTimestamp(timestamp, format = 'seconds') {
  const now = Date.now() / 1000; // Current time in seconds
  const minDate = 0; // Unix epoch
  const maxDate = now + (100 * 365 * 24 * 60 * 60); // 100 years in future

  if (format === 'seconds') {
    if (timestamp < minDate || timestamp > maxDate) {
      throw new Error('Invalid Unix timestamp (seconds)');
    }
  } else if (format === 'milliseconds') {
    const timestampSeconds = timestamp / 1000;
    if (timestampSeconds < minDate || timestampSeconds > maxDate) {
      throw new Error('Invalid Unix timestamp (milliseconds)');
    }
  }

  return true;
}

Language-Specific Examples

Python (seconds) to JavaScript (milliseconds)

# Python backend
import time
timestamp = int(time.time())  # 1735689600 (seconds)

# Send to frontend
return jsonify({'timestamp': timestamp})
// JavaScript frontend
fetch('/api/time')
  .then(r => r.json())
  .then(data => {
    const date = new Date(data.timestamp * 1000); // Convert to ms
    console.log(date);
  });

JavaScript (milliseconds) to PHP (seconds)

// JavaScript frontend
const timestamp = Date.now(); // 1735689600000 (milliseconds)

fetch('/api/save', {
  method: 'POST',
  body: JSON.stringify({
    timestamp: Math.floor(timestamp / 1000) // Convert to seconds
  })
});
// PHP backend
$timestamp = $_POST['timestamp']; // 1735689600 (seconds)
$date = date('Y-m-d H:i:s', $timestamp);

Conclusion

The difference between Unix timestamps in seconds and milliseconds is one of the most important distinctions in cross-platform time handling. Remember these key points:

  1. Seconds (10 digits) are used by most backend systems, databases, and Unix tools
  2. Milliseconds (13 digits) are used by JavaScript, Java, and some modern APIs
  3. Always convert explicitly when crossing language boundaries
  4. Document your API format clearly to prevent confusion
  5. Use digit count or magnitude checks to detect format automatically when needed

By understanding and properly handling these formats, you'll avoid one of the most common categories of bugs in web development and ensure your applications handle time correctly across all platforms.

Need to convert between Unix timestamp formats? Try our Unix Timestamp Converter for instant, accurate conversions with timezone support.

Frequently Asked Questions

How do I know if a Unix timestamp is in seconds or milliseconds?

Count the digits. In the current era a seconds timestamp is about 10 digits (for example 1735689600) and a milliseconds timestamp is about 13 digits (1735689600000) — the milliseconds value is just the seconds value with three extra zeros on the end. A reliable programmatic rule: if the number is below 10,000,000,000 (ten billion) treat it as seconds, otherwise treat it as milliseconds. Ten billion seconds lands in the year 2286, so any "normal" present-day date that exceeds it must actually be milliseconds.

How do I convert milliseconds to seconds?

Divide by 1000 and drop the fraction. In JavaScript use Math.floor(ms / 1000) so you get a whole number of seconds — plain division leaves a decimal like 1735689600.123, which most back-end systems and database columns will reject or truncate unpredictably. In Python it is int(ms / 1000) or ms // 1000. The floor (not round) matters because Unix seconds count completed seconds since the epoch.

How do I convert seconds to milliseconds?

Multiply by 1000. A Unix seconds value like 1735689600 becomes 1735689600000. In JavaScript this is the step people forget when building a Date: new Date(seconds * 1000) is correct, while new Date(seconds) treats the number as milliseconds and produces a date in January 1970. Whenever you feed a back-end (seconds) timestamp into a JavaScript Date, multiply by 1000 first.

Why does a millisecond timestamp have 13 digits?

Because it counts a thousand times as many units as a seconds timestamp for the same moment, and 1000 is three orders of magnitude — so the value gains three digits. A ~10-digit seconds count times 1000 becomes a ~13-digit milliseconds count. This 10-vs-13 relationship holds for every date between September 2001 (when seconds crossed into 10 digits) and the year 2286 (when seconds reaches 11 digits), which covers essentially all timestamps you will meet in practice.

Why does JavaScript use milliseconds instead of seconds?

JavaScript's Date object was modeled on Java's java.util.Date, which used millisecond resolution for finer timing, so Date.now(), new Date().getTime(), and the Date constructor all speak milliseconds. Most Unix tooling, databases, and back-end languages (PHP, Python, Ruby, Go) speak seconds. That mismatch at the browser/server boundary is the single most common source of "my date is off by decades" bugs — convert explicitly every time data crosses it.

What about microsecond and nanosecond timestamps?

They exist and follow the same digit-length logic. Microseconds since the epoch are about 16 digits (Python's time.time_ns() // 1000, or database engines that store microsecond precision), and nanoseconds are about 19 digits (Go's time.Now().UnixNano(), Python's time.time_ns()). To normalize to seconds, divide microseconds by 1,000,000 and nanoseconds by 1,000,000,000. As a quick tell: ~10 digits = seconds, ~13 = milliseconds, ~16 = microseconds, ~19 = nanoseconds.

Why does my converted date show 1970 or the year 56970?

Both are unit-mismatch symptoms. A date stuck near January 1970 means you fed a seconds value into something expecting milliseconds (the number was 1000x too small) — multiply by 1000. A wildly future year like 56970 means you fed a milliseconds value into something expecting seconds (1000x too large) — divide by 1000. The direction of the error tells you exactly which conversion you missed.

Does counting digits always work to detect the format?

It works for everyday dates but has edges. Dates before September 9, 2001 have 9-or-fewer-digit seconds values, and dates before 1970 are negative, so a naive length check misclassifies them. The magnitude test (below ten billion = seconds) is more robust than raw digit-counting, but the truly safe approach is to know your data source's contract — JavaScript and Java emit milliseconds, Unix and most databases emit seconds — rather than guess from the value alone.

unixtimestampjavascriptdatetimeconversion