Unix Timestamps: Milliseconds vs Seconds (and Why It Causes Bugs)

Why does JavaScript use 13-digit millisecond timestamps while Unix natively uses 10-digit second timestamps? A comprehensive guide to timestamp precision.

Quick Summary
Standard Unix systems measure time in Seconds (a 10-digit number like 1716300000). JavaScript and Java measure time in Milliseconds (a 13-digit number like 1716300000000). Mixing these up is one of the most common causes of bugs in web development, usually resulting in dates unexpectedly parsing as January 1970.


Introduction

If you have been working in web development for more than a few months, you have almost certainly encountered a bug where a user's creation date, a blog post publish date, or an event schedule suddenly rendered as "January 17, 1970".

This is a rite of passage for frontend and backend developers alike. It is caused by the fundamental mismatch in time precision between standard operating systems (which track time in seconds) and modern web languages like JavaScript (which track time in milliseconds).



The Unix Standard: 10 Digits

As discussed in our broader Unix Epoch guide, Unix time is defined as the number of elapsed seconds since January 1st, 1970.

When Unix was created, 1 second of precision was considered more than enough. It allowed the timestamp to easily fit inside a highly efficient 32-bit integer. Because we are currently around 1.7 billion seconds past the epoch, a standard Unix timestamp is a 10-digit number.

If your database, backend (like PHP or Go), or a third-party API returns an integer for a date, you can safely assume 99% of the time that it is a 10-digit second timestamp.



The JavaScript Standard: 13 Digits

When Brendan Eich invented JavaScript in 1995, he explicitly modeled its Date object on Java's java.util.Date class. Java made the decision to track time in milliseconds (1/1000th of a second) to allow for more precise event tracking and benchmarking.

Because there are 1,000 milliseconds in a second, a JavaScript timestamp is significantly larger than a Unix timestamp. Today, a JS timestamp is a 13-digit number.



The Classic "1970 Bug"

The bug occurs during the handshake between the backend and the frontend. Let's look at the lifecycle of the error:

  1. Your backend Python server creates an account and logs the timestamp: 1716300000.
  2. The frontend receives the data and passes it to the JS Date constructor: new Date(1716300000).
  3. JavaScript expects 13 digits. It sees the 10-digit number and assumes only 1.7 billion milliseconds have passed since the epoch.
  4. 1.7 billion milliseconds is exactly 1,716,300 seconds, which is about 19.8 days.
  5. JavaScript renders the date as January 19th, 1970.
The Fix
The fix is incredibly simple. When receiving a 10-digit timestamp from a server, immediately multiply it by 1000 before passing it to the JavaScript Date object: new Date(timestamp * 1000).


Microseconds and Nanoseconds

As computers became drastically faster, even milliseconds (1/1000th of a second) weren't precise enough. Trading systems, high-frequency logging, and performance profiling now require significantly deeper precision.

  • Microseconds: 1/1,000,000th of a second. (16 digits). Supported natively by Python and PostgreSQL.
  • Nanoseconds: 1/1,000,000,000th of a second. (19 digits). Natively used by Go (Golang) and the process.hrtime() API in Node.js.

If you receive an incredibly long integer timestamp and don't know what it is, count the digits: 10 (Seconds), 13 (Milliseconds), 16 (Microseconds), 19 (Nanoseconds).



Database Storage Considerations

If you decide to store raw integer timestamps in your database (instead of a native DATETIME column), you must use the correct column type.

A standard 10-digit Unix timestamp (Seconds) will fit inside a standard 32-bit INT column until the year 2038. However, a 13-digit JavaScript timestamp (Milliseconds) massively overflows a 32-bit integer.

If you attempt to insert a 13-digit JS timestamp into a standard SQL INT column, it will max out at 2147483647. To store milliseconds, microseconds, or nanoseconds, you must use a BIGINT (64-bit) column.



Safe Conversion Cheatsheet

JavaScript

// 1. Get current time in Milliseconds (13 digits)
const msTime = Date.now(); 

// 2. Safely generate a Seconds timestamp (10 digits) to send to backend
const secTime = Math.floor(Date.now() / 1000);

// 3. Parse a backend Seconds timestamp into JS
const backendTimestamp = 1716300000;
const dateObject = new Date(backendTimestamp * 1000);

Python

import time
from datetime import datetime

# 1. Get current time in Seconds (10 digits)
sec_time = int(time.time())

# 2. Get current time in Milliseconds (13 digits)
ms_time = int(time.time() * 1000)

# 3. Parse a frontend JS Millisecond timestamp
js_timestamp = 1716300000000
date_object = datetime.fromtimestamp(js_timestamp / 1000.0)


Frequently Asked Questions

Why is my JavaScript date showing January 1970?

This happens when you pass a 10-digit standard Unix timestamp (seconds) into the JavaScript Date object, which expects 13 digits (milliseconds). The engine interprets your timestamp as a few thousand milliseconds after the Epoch, resulting in a date in early January 1970. Multiply the incoming timestamp by 1000 to fix it.

How do I convert milliseconds to seconds?

Divide the millisecond timestamp by 1000 and round down using Math.floor(). For example: Math.floor(Date.now() / 1000);

Try It Yourself

Not sure if the integer you are looking at is in seconds or milliseconds? Paste it into our smart converter.