Unix Timestamps Explained: Working with Epoch Time
Everything you need to know about Unix timestamps. Learn conversions in JavaScript, Python, PHP, SQL, and Bash. Includes the 2038 problem and common pitfalls.
Unix timestamps are everywhere in programming - databases, APIs, logs, file systems. Understanding how they work helps you handle dates correctly across time zones and avoid common pitfalls.
What is a Unix Timestamp?
A Unix timestamp (also called Unix time, POSIX time, or Epoch time) is the number of seconds that have elapsed since January 1, 1970, 00:00:00 UTC. This moment is called the Unix Epoch.
Unix Epoch: January 1, 1970, 00:00:00 UTC
Timestamp: 0
Right now: January 15, 2025, 12:00:00 UTC
Timestamp: 1736942400
It's simply a count of seconds - no time zones, no formatting, no ambiguity.
Why Use Timestamps?
1. Universal and Unambiguous
A timestamp means the same thing everywhere in the world:
Timestamp: 1704067200
In New York: 2024-01-01 00:00:00 EST
In London: 2024-01-01 05:00:00 GMT
In Tokyo: 2024-01-01 14:00:00 JST
All the same instant in time.
2. Easy to Compare and Sort
// Which is earlier? Simple number comparison
const event1 = 1704067200;
const event2 = 1704153600;
if (event1 < event2) {
console.log("Event 1 happened first");
}
// Sort chronologically
const events = [1704153600, 1704067200, 1704240000];
events.sort((a, b) => a - b); // Ascending order
3. Easy Arithmetic
const now = 1704067200;
// Add 1 hour (3600 seconds)
const oneHourLater = now + 3600;
// Add 1 day (86400 seconds)
const oneDayLater = now + 86400;
// Add 1 week
const oneWeekLater = now + (7 * 86400);
// Time between two events
const duration = event2 - event1; // seconds apart
4. Storage Efficient
String: "2024-01-01T00:00:00.000Z" (24 bytes)
Timestamp: 1704067200 (4-8 bytes)
Seconds vs Milliseconds
Different systems use different precision:
| Precision | Example | Used By |
|---|---|---|
| Seconds | 1704067200 | Unix, PHP, Python, SQL, most APIs |
| Milliseconds | 1704067200000 | JavaScript, Java, some APIs |
| Microseconds | 1704067200000000 | High-precision systems |
| Nanoseconds | 1704067200000000000 | Go, some databases |
How to tell them apart:
- 10 digits = seconds (covers years 1970-2286)
- 13 digits = milliseconds
- 16 digits = microseconds
- 19 digits = nanoseconds
// Convert between them
const seconds = 1704067200;
const milliseconds = seconds * 1000;
const microseconds = seconds * 1000000;
// Convert back
const backToSeconds = Math.floor(milliseconds / 1000);
Working with Timestamps in Different Languages
JavaScript
// Get current timestamp
Date.now(); // Milliseconds
Math.floor(Date.now() / 1000); // Seconds
// Create timestamp from date
new Date('2024-01-01').getTime(); // Milliseconds
new Date('2024-01-01').getTime() / 1000; // Seconds
// Convert timestamp to Date
new Date(1704067200 * 1000); // From seconds
new Date(1704067200000); // From milliseconds
// Format a timestamp
new Date(1704067200 * 1000).toISOString();
// "2024-01-01T00:00:00.000Z"
new Date(1704067200 * 1000).toLocaleString('en-US', {
timeZone: 'America/New_York'
});
// "12/31/2023, 7:00:00 PM"
Python
import time
from datetime import datetime, timezone
# Get current timestamp
int(time.time()) # Seconds
time.time_ns() // 1_000_000 # Milliseconds
# Create timestamp from date
datetime(2024, 1, 1, tzinfo=timezone.utc).timestamp()
# Convert timestamp to datetime
datetime.fromtimestamp(1704067200, tz=timezone.utc)
# Format
datetime.fromtimestamp(1704067200, tz=timezone.utc).isoformat()
# "2024-01-01T00:00:00+00:00"
PHP
// Get current timestamp
time(); // Seconds
microtime(true) * 1000; // Milliseconds
// Create timestamp from date
strtotime('2024-01-01');
// Convert timestamp to date
date('Y-m-d H:i:s', 1704067200);
// "2024-01-01 00:00:00"
// With DateTime
$dt = new DateTime('@1704067200');
$dt->setTimezone(new DateTimeZone('UTC'));
echo $dt->format('c');
// "2024-01-01T00:00:00+00:00"
SQL
-- MySQL
SELECT UNIX_TIMESTAMP(); -- Current timestamp
SELECT UNIX_TIMESTAMP('2024-01-01'); -- Date to timestamp
SELECT FROM_UNIXTIME(1704067200); -- Timestamp to date
-- PostgreSQL
SELECT EXTRACT(EPOCH FROM NOW()); -- Current timestamp
SELECT EXTRACT(EPOCH FROM TIMESTAMP '2024-01-01');
SELECT TO_TIMESTAMP(1704067200); -- Timestamp to date
-- SQLite
SELECT strftime('%s', 'now'); -- Current timestamp
SELECT datetime(1704067200, 'unixepoch'); -- Timestamp to date
Bash
# Get current timestamp
date +%s
# Convert timestamp to date
date - d @1704067200 # Linux
date - r 1704067200 # macOS
# Convert date to timestamp
date - d "2024-01-01" +%s # Linux
date - j - f "%Y-%m-%d" "2024-01-01" +%s # macOS
Common Time Intervals
Memorize these for quick calculations:
| Interval | Seconds | Notes |
|---|---|---|
| 1 minute | 60 | |
| 1 hour | 3,600 | 60 × 60 |
| 1 day | 86,400 | 24 × 3,600 |
| 1 week | 604,800 | 7 × 86,400 |
| 30 days | 2,592,000 | |
| 1 year | 31,536,000 | 365 days |
| 1 leap year | 31,622,400 | 366 days |
// Useful constants
const MINUTE = 60;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
const WEEK = 7 * DAY;
// Calculate expiration (1 week from now)
const expires = Math.floor(Date.now() / 1000) + WEEK;
Important Timestamps
| Event | Timestamp | Date (UTC) |
|---|---|---|
| Unix Epoch | 0 | 1970-01-01 00:00:00 |
| First moon landing | -14182940 | 1969-07-20 20:17:40 |
| Y2K | 946684800 | 2000-01-01 00:00:00 |
| 32-bit overflow | 2147483647 | 2038-01-19 03:14:07 |
| Bitcoin genesis block | 1231006505 | 2009-01-03 18:15:05 |
| 1 billion seconds | 1000000000 | 2001-09-09 01:46:40 |
| 2 billion seconds | 2000000000 | 2033-05-18 03:33:20 |
The Year 2038 Problem
32-bit signed integers can only store values up to 2,147,483,647. This represents:
Maximum 32-bit timestamp: 2147483647
Date: Tuesday, January 19, 2038, 03:14:07 UTC
One second later, the timestamp overflows to a negative number, which represents a date in 1901:
Overflowed value: -2147483648
Interpreted as: December 13, 1901
Who's Affected?
- Older 32-bit systems
- Embedded systems (IoT devices, cars, appliances)
- Databases using 32-bit integer columns
- Legacy code that hasn't been updated
The Solution
Use 64-bit timestamps. A signed 64-bit integer can represent dates until the year 292 billion:
64-bit max: 9,223,372,036,854,775,807
Date: About 292 billion years from now
// JavaScript uses 64-bit floats, so it's safe
// But some APIs might use 32-bit integers
// Always use BigInt for very large timestamps
const farFuture = BigInt(Date.now()) + BigInt(1000000000000);
Common Pitfalls
1. Confusing Seconds and Milliseconds
// Wrong: treating seconds as milliseconds
new Date(1704067200); // 1970-01-20 (way off!)
// Correct: multiply by 1000
new Date(1704067200 * 1000); // 2024-01-01
2. Time Zone Confusion
// Timestamp is always UTC, but display is local
const ts = 1704067200;
// This shows LOCAL time, not UTC
console.log(new Date(ts * 1000).toString());
// Might show Dec 31, 2023 in some time zones
// To show UTC explicitly
console.log(new Date(ts * 1000).toUTCString());
// "Mon, 01 Jan 2024 00:00:00 GMT"
3. Daylight Saving Time
Timestamps don't have DST issues - they're always in UTC. But converting to local time can be tricky:
// Adding 24 hours doesn't always mean "same time tomorrow"
// in local time during DST transitions!
// Always do date math in UTC or use a proper library
4. Negative Timestamps
Dates before 1970 have negative timestamps:
// Moon landing: July 20, 1969
const moonLanding = -14182940;
// Works fine in most systems
new Date(moonLanding * 1000);
// "Sun Jul 20 1969 20:17:40 GMT+0000"
Best Practices
- Store timestamps in UTC - Always use Unix timestamps or UTC datetime
- Convert to local time only for display - Never store local times
- Use 64-bit integers - Avoid the 2038 problem
- Be explicit about precision - Document whether you're using seconds or milliseconds
- Use libraries for complex date math - Moment.js, date-fns, Luxon, or Day.js
- Validate timestamps - Check for reasonable ranges
function isValidTimestamp(ts) {
// Reasonable range: 1970 to 2100
const MIN = 0;
const MAX = 4102444800; // 2100-01-01
return Number.isInteger(ts) && ts >= MIN && ts <= MAX;
}
Quick Reference
// Current timestamp (seconds)
Math.floor(Date.now() / 1000)
// Timestamp → Date
new Date(timestamp * 1000)
// Date → Timestamp
Math.floor(new Date('2024-01-01').getTime() / 1000)
// Add time
timestamp + 3600 // +1 hour
timestamp + 86400 // +1 day
timestamp + 604800 // +1 week
// Format as ISO string
new Date(timestamp * 1000).toISOString()
Use our Timestamp Converter to quickly convert between timestamps and human-readable dates.
Related Tools
Related Articles
Try Our Free Tools
200+ browser-based tools for developers and creators. No uploads, complete privacy.
Explore All Tools