Unix Timestamps in JavaScript
JavaScript's Date object is the primary interface for working with timestamps. It uses milliseconds since the Unix epoch internally, which is an important distinction from most server-side languages that default to seconds. This guide covers every practical timestamp operation in both browser and Node.js environments.
Getting the Current Timestamp
There are three common ways to get the current time as a number. They all return milliseconds.
Date.now()
const ms = Date.now();
console.log(ms); // 1711545600123
This is the preferred approach. It is a static method that does not create a Date object, making it the fastest option.
new Date().getTime()
const ms = new Date().getTime();
console.log(ms); // 1711545600123
Creates a Date object first, then extracts the timestamp. Use this when you also need the Date object for formatting.
+new Date()
const ms = +new Date();
console.log(ms); // 1711545600123
The unary + operator coerces the Date to its numeric value. This works but is less readable than Date.now(). You may see it in older codebases.
Seconds Instead of Milliseconds
Since JavaScript uses milliseconds natively, divide by 1000 to get Unix seconds:
const seconds = Math.floor(Date.now() / 1000);
console.log(seconds); // 1711545600
Use Math.floor() rather than Math.round() to avoid accidentally jumping forward by a second.
Converting a Timestamp to a Date Object
From Milliseconds
const date = new Date(1711545600123);
console.log(date.toISOString()); // "2024-03-27T12:00:00.123Z"
From Seconds
If your timestamp is in seconds (10 digits), multiply by 1000 first:
const date = new Date(1711545600 * 1000);
console.log(date.toISOString()); // "2024-03-27T12:00:00.000Z"
Forgetting to multiply is one of the most common timestamp bugs in JavaScript. A 10-digit number passed directly to new Date() will produce a date in January 1970.
Formatting Dates
Built-in Methods
const date = new Date(1711545600000);
date.toISOString(); // "2024-03-27T12:00:00.000Z" - always UTC
date.toUTCString(); // "Wed, 27 Mar 2024 12:00:00 GMT" - HTTP date format
date.toLocaleDateString(); // "3/27/2024" - locale-dependent
date.toLocaleTimeString(); // "8:00:00 AM" - locale-dependent
date.toLocaleString(); // "3/27/2024, 8:00:00 AM" - locale-dependent
Intl.DateTimeFormat
For full control over locale-aware formatting:
const date = new Date(1711545600000);
const fmt = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
timeZone: "America/New_York",
timeZoneName: "short",
});
console.log(fmt.format(date)); // "March 27, 2024, 08:00 AM EDT"
Intl.DateTimeFormat supports every IANA timezone and is available in all modern browsers and Node.js. It eliminates the need for timezone libraries in many cases.
Custom Formatting Without Libraries
function formatTimestamp(ms) {
const d = new Date(ms);
const pad = (n) => String(n).padStart(2, "0");
return (
`${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ` +
`${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
);
}
console.log(formatTimestamp(1711545600000)); // "2024-03-27 12:00:00"
Note that getMonth() is 0-indexed (January is 0, December is 11). This is the single most common source of date bugs in JavaScript.
Milliseconds vs Seconds
| Context | Unit | Digits | Example |
|---|---|---|---|
Date.now() | milliseconds | 13 | 1711545600123 |
Unix command date +%s | seconds | 10 | 1711545600 |
| Most REST APIs | varies | 10 or 13 | check the docs |
A quick detection rule: 10 digits = seconds, 13 digits = milliseconds. If the number starts with 17... and has 10 digits, it is seconds in the 2020s era. If it has 13 digits, it is milliseconds.
function toMilliseconds(ts) {
return ts < 1e12 ? ts * 1000 : ts;
}
Node.js Specific APIs
process.hrtime.bigint()
Returns the current high-resolution time in nanoseconds as a BigInt. Useful for measuring elapsed time with sub-millisecond precision:
const start = process.hrtime.bigint();
// ... some operation ...
const elapsed = process.hrtime.bigint() - start;
console.log(`${elapsed}ns`); // "1234567ns"
This is not related to the Unix epoch. It measures time from an arbitrary point (usually process start). Use it for benchmarks, not for generating timestamps.
performance.now()
Available in both browsers and Node.js. Returns a high-resolution float in milliseconds:
const start = performance.now();
// ... some operation ...
const elapsed = performance.now() - start;
console.log(`${elapsed.toFixed(2)}ms`); // "1.23ms"
Like hrtime, this is for measuring durations, not for calendar timestamps.
Parsing Date Strings
// ISO 8601 - safe and reliable
new Date("2024-03-27T12:00:00Z").getTime(); // 1711540800000
// Date-only strings are parsed as UTC
new Date("2024-03-27").getTime(); // 1711497600000 (midnight UTC)
// Date-time without Z or offset is parsed as LOCAL time
new Date("2024-03-27T12:00:00").getTime(); // depends on your timezone!
Rule of thumb: Always include a timezone indicator (Z for UTC, or an offset like +05:30) in date strings. Omitting it leads to inconsistent behavior across environments.
Common Gotchas
| Gotcha | Fix |
|---|---|
getMonth() returns 0-11 | Add 1 for human-readable months |
new Date(seconds) gives 1970 date | Multiply by 1000: new Date(seconds * 1000) |
Date.parse("03/27/2024") is locale-dependent | Use ISO format: "2024-03-27" |
new Date("2024-03-27") is UTC but new Date("2024-03-27T00:00:00") is local | Always append Z or an offset |
Two Date objects with same time are not === | Compare with .getTime(): a.getTime() === b.getTime() |
typeof new Date() is "object" not "date" | Use instanceof Date to check type |
Quick Reference
// Current timestamp (ms)
Date.now()
// Current timestamp (seconds)
Math.floor(Date.now() / 1000)
// Timestamp to Date
new Date(ms)
new Date(seconds * 1000)
// Date to timestamp
date.getTime()
// Format as ISO string
date.toISOString()
// Format for specific timezone
new Intl.DateTimeFormat("en", { timeZone: "Asia/Tokyo" }).format(date)
Need to verify a conversion or debug a timestamp from your logs? Try it online with DevToolBox -- paste any timestamp and see it decoded instantly.