TL;DR
A Unix timestamp counts the seconds since 1970-01-01 00:00:00 UTC. JavaScript uses milliseconds β divide by 1000 for seconds. Python has time.time(), Go has time.Now().Unix(). Always store UTC, always check if you have ms (13 digits) or s (10 digits). Use our free Unix Timestamp Converter to instantly convert between timestamps and human-readable dates online.
What Is a Unix Timestamp?
A Unix timestamp (also known as Epoch time, POSIX time, or Unix time) is an integer representing the number of seconds elapsed since the Unix epoch β January 1, 1970, at 00:00:00 Coordinated Universal Time (UTC). This starting point was chosen for the Unix operating system and has since become the universal standard for machine-readable time across every programming language, database, and operating system.
As of 2024, the current Unix timestamp is approximately 1.7 billion (seconds). This grows by 1 every second. Unlike human-readable date strings, a Unix timestamp carries no ambiguity about timezone β it is always UTC.
Unix Timestamp vs ISO 8601 vs RFC 2822
| Format | Example | Human Readable | Timezone | Use Case |
|---|---|---|---|---|
| Unix Timestamp | 1709049600 | No | Always UTC | Storage, arithmetic, APIs |
| ISO 8601 | 2024-02-27T12:00:00Z | Yes | Explicit (Z = UTC) | JSON APIs, logs, HTML datetime |
| RFC 2822 | Tue, 27 Feb 2024 12:00:00 +0000 | Yes | Offset required | Email headers, HTTP Date header |
Get the Current Unix Timestamp
Here is how to get the current timestamp in the most popular languages:
JavaScript
// Milliseconds (13 digits) β JavaScript's native unit
const ms = Date.now();
console.log(ms); // e.g. 1709049600000
// Seconds (10 digits) β standard Unix timestamp
const s = Math.floor(Date.now() / 1000);
console.log(s); // e.g. 1709049600
// Alternative using new Date()
const s2 = Math.floor(new Date().getTime() / 1000);Python
import time
from datetime import datetime
# Float (seconds with fractional part)
ts_float = time.time()
print(ts_float) # e.g. 1709049600.123456
# Integer seconds
ts_int = int(time.time())
print(ts_int) # e.g. 1709049600
# Using datetime
ts_dt = int(datetime.now().timestamp())
print(ts_dt) # e.g. 1709049600Go
package main
import (
"fmt"
"time"
)
func main() {
// Seconds
s := time.Now().Unix()
fmt.Println(s) // e.g. 1709049600
// Milliseconds
ms := time.Now().UnixMilli()
fmt.Println(ms) // e.g. 1709049600000
// Nanoseconds
ns := time.Now().UnixNano()
fmt.Println(ns)
}Bash
# Standard Unix timestamp (seconds)
date +%s
# Output: 1709049600
# With milliseconds (GNU date)
date +%s%3N
# Output: 1709049600123Convert a Unix Timestamp to a Date
Converting a Unix timestamp back to a human-readable date is a daily developer task. Here are the idiomatic ways in each language. Try our timestamp converter tool for instant online conversions.
JavaScript
const ts = 1709049600; // Unix seconds
// Multiply by 1000 β JS Date expects milliseconds!
const date = new Date(ts * 1000);
// ISO 8601 string (UTC)
console.log(date.toISOString()); // "2024-02-27T12:00:00.000Z"
// Locale-specific string (user's browser timezone)
console.log(date.toLocaleString()); // "2/27/2024, 12:00:00 PM" (varies)
// Custom formatting
const formatted = date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
timeZone: 'UTC',
});
console.log(formatted); // "February 27, 2024"Python
from datetime import datetime
ts = 1709049600
# Local time (uses system timezone β be careful!)
local_dt = datetime.fromtimestamp(ts)
print(local_dt) # 2024-02-27 12:00:00 (local)
# UTC time (always safe)
utc_dt = datetime.utcfromtimestamp(ts)
print(utc_dt) # 2024-02-27 12:00:00
# ISO 8601 format
print(utc_dt.strftime('%Y-%m-%dT%H:%M:%SZ')) # 2024-02-27T12:00:00Z
# With timezone using zoneinfo (Python 3.9+)
from zoneinfo import ZoneInfo
tz_dt = datetime.fromtimestamp(ts, tz=ZoneInfo('America/New_York'))
print(tz_dt) # 2024-02-27 07:00:00-05:00Go
package main
import (
"fmt"
"time"
)
func main() {
ts := int64(1709049600)
// Convert Unix seconds to time.Time (UTC)
t := time.Unix(ts, 0).UTC()
fmt.Println(t) // 2024-02-27 12:00:00 +0000 UTC
fmt.Println(t.Format(time.RFC3339)) // 2024-02-27T12:00:00Z
fmt.Println(t.Format("2006-01-02")) // 2024-02-27
// Convert Unix milliseconds to time.Time
ms := int64(1709049600000)
tms := time.UnixMilli(ms).UTC()
fmt.Println(tms.Format(time.RFC3339)) // 2024-02-27T12:00:00Z
}PHP
<?php
$ts = 1709049600;
// Format directly from Unix timestamp
echo date('Y-m-d H:i:s', $ts); // 2024-02-27 12:00:00 (local TZ)
// With DateTimeImmutable (recommended)
$dt = new DateTimeImmutable('@' . $ts); // '@' prefix = Unix timestamp
echo $dt->format('Y-m-d H:i:s'); // 2024-02-27 12:00:00
// Force UTC
$dtUtc = new DateTimeImmutable('@' . $ts, new DateTimeZone('UTC'));
echo $dtUtc->format(DateTime::ATOM); // 2024-02-27T12:00:00+00:00Convert a Date to a Unix Timestamp
The reverse conversion β from a human-readable date to a Unix timestamp β is equally common, especially when building search filters, expiry dates, or scheduled tasks.
JavaScript
// From a date string β returns seconds
const ts = Math.floor(new Date('2024-01-15').getTime() / 1000);
console.log(ts); // 1705276800
// From explicit UTC values (avoids local timezone ambiguity)
const tsUtc = Math.floor(Date.UTC(2024, 0, 15) / 1000); // month is 0-indexed!
console.log(tsUtc); // 1705276800
// From a specific time
const tsWithTime = Math.floor(new Date('2024-01-15T10:30:00Z').getTime() / 1000);
console.log(tsWithTime); // 1705314600Python
from datetime import datetime, timezone
import calendar
# Local time (system timezone) β can be surprising!
dt_local = datetime(2024, 1, 15)
ts_local = int(dt_local.timestamp())
print(ts_local) # varies by system timezone
# UTC (always explicit)
dt_utc = datetime(2024, 1, 15, tzinfo=timezone.utc)
ts_utc = int(dt_utc.timestamp())
print(ts_utc) # 1705276800
# Using calendar.timegm for naive UTC datetime
dt_naive = datetime(2024, 1, 15, 10, 30, 0)
ts_cal = calendar.timegm(dt_naive.timetuple())
print(ts_cal) # 1705314600Go
package main
import (
"fmt"
"time"
)
func main() {
// Create a specific UTC date and get its Unix timestamp
t := time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC)
fmt.Println(t.Unix()) // 1705276800
// Parse from ISO 8601 string
parsed, _ := time.Parse(time.RFC3339, "2024-01-15T10:30:00Z")
fmt.Println(parsed.Unix()) // 1705314600
}Milliseconds vs Seconds β The #1 Source of Timestamp Bugs
The single most common timestamp bug is mixing up millisecond and second precision. JavaScript natively works with milliseconds, while the Unix standard and most other languages use seconds.
| Unit | Digits (2024) | Example | Languages / Systems |
|---|---|---|---|
| Seconds | 10 digits | 1709049600 | Unix, Python, PHP, Go, C, MySQL, PostgreSQL |
| Milliseconds | 13 digits | 1709049600000 | JavaScript, Java, Dart, Kotlin, Elasticsearch |
| Microseconds | 16 digits | 1709049600000000 | PostgreSQL TIMESTAMPTZ, C++ chrono |
How to Detect the Unit at Runtime
// JavaScript: detect ms vs s
function toSeconds(ts) {
// If the timestamp is greater than 1e10, it's in milliseconds
return ts > 1e10 ? Math.floor(ts / 1000) : ts;
}
console.log(toSeconds(1709049600)); // 1709049600 (already seconds)
console.log(toSeconds(1709049600000)); // 1709049600 (converted from ms)
// Python equivalent
def to_seconds(ts):
return ts // 1000 if ts > 1e10 else tsTimezone Handling β Avoid the UTC vs Local Trap
Unix timestamps are always UTC. The confusion arises when converting them to human-readable strings β some APIs produce local time, others UTC. Understanding this is essential for avoiding subtle timezone bugs.
JavaScript β UTC vs Browser Timezone
const ts = 1709049600; // 2024-02-27 12:00:00 UTC
const date = new Date(ts * 1000);
// ALWAYS UTC β safe for storage/display in UTC contexts
console.log(date.toISOString()); // "2024-02-27T12:00:00.000Z"
// USES BROWSER TIMEZONE β output depends on user's locale!
console.log(date.toLocaleDateString()); // varies: "2/27/2024" or "27.02.2024"
// Explicit timezone using Intl.DateTimeFormat
const fmt = new Intl.DateTimeFormat('en-US', {
timeZone: 'America/New_York',
dateStyle: 'full',
timeStyle: 'long',
});
console.log(fmt.format(date)); // "Tuesday, February 27, 2024 at 7:00:00 AM EST"Python β Local vs UTC vs Named Timezone
from datetime import datetime, timezone
from zoneinfo import ZoneInfo # Python 3.9+
ts = 1709049600
# Local (system timezone β avoid in production code)
print(datetime.fromtimestamp(ts)) # Local time
# UTC (always explicit, always the same)
print(datetime.fromtimestamp(ts, tz=timezone.utc)) # 2024-02-27 12:00:00+00:00
# Named timezone
ny = ZoneInfo('America/New_York')
print(datetime.fromtimestamp(ts, tz=ny)) # 2024-02-27 07:00:00-05:00
tokyo = ZoneInfo('Asia/Tokyo')
print(datetime.fromtimestamp(ts, tz=tokyo)) # 2024-02-27 21:00:00+09:00
# Using pytz (older projects)
import pytz
eastern = pytz.timezone('America/New_York')
dt = datetime.fromtimestamp(ts, tz=eastern)
print(dt) # 2024-02-27 07:00:00-05:00Best practice: Always store timestamps as UTC integers in your database. Convert to the user's timezone only at the presentation layer using their stored preference.
JavaScript Date Arithmetic
Adding and subtracting time intervals is straightforward with Unix timestamps β simply use arithmetic on the integer values.
const now = Date.now(); // milliseconds
// Add 7 days
const sevenDaysLater = new Date(now + 7 * 24 * 60 * 60 * 1000);
console.log(sevenDaysLater.toISOString());
// Subtract 30 days
const thirtyDaysAgo = new Date(now - 30 * 24 * 60 * 60 * 1000);
console.log(thirtyDaysAgo.toISOString());
// Calculate duration between two timestamps (in seconds)
const start = 1709049600;
const end = 1709136000;
const durationSecs = end - start;
const hours = Math.floor(durationSecs / 3600);
const minutes = Math.floor((durationSecs % 3600) / 60);
console.log(`Duration: ${hours}h ${minutes}m`); // Duration: 24h 0m
// Using date-fns library (recommended for complex date math)
// import { addDays, subDays, differenceInDays } from 'date-fns';
// const nextWeek = addDays(new Date(), 7);
// const diff = differenceInDays(new Date('2024-12-31'), new Date('2024-01-01'));
// console.log(diff); // 365Go β The time Package
Go's time package provides comprehensive timestamp functionality. A key detail: Go's reference time is Mon Jan 2 15:04:05 MST 2006 β use these exact values in format strings.
package main
import (
"fmt"
"time"
)
func main() {
// Current timestamp
nowUnix := time.Now().Unix() // seconds
nowMilli := time.Now().UnixMilli() // milliseconds
nowNano := time.Now().UnixNano() // nanoseconds
fmt.Println(nowUnix, nowMilli, nowNano)
// Timestamp to time.Time
ts := int64(1709049600)
t := time.Unix(ts, 0).UTC()
// Formatting (Go uses the reference time Mon Jan 2 15:04:05 MST 2006)
fmt.Println(t.Format(time.RFC3339)) // 2024-02-27T12:00:00Z
fmt.Println(t.Format("2006-01-02")) // 2024-02-27
fmt.Println(t.Format("Jan 2, 2006 3:04 PM")) // Feb 27, 2024 12:00 PM
// Parsing a string to time.Time
parsed, err := time.Parse(time.RFC3339, "2024-01-15T10:30:00Z")
if err == nil {
fmt.Println(parsed.Unix()) // 1705314600
}
// Date arithmetic
tomorrow := t.Add(24 * time.Hour)
fmt.Println(tomorrow.Format("2006-01-02")) // 2024-02-28
lastWeek := t.Add(-7 * 24 * time.Hour)
fmt.Println(lastWeek.Format("2006-01-02")) // 2024-02-20
// Duration between two times
t2, _ := time.Parse(time.RFC3339, "2024-03-01T00:00:00Z")
duration := t2.Sub(t)
fmt.Printf("%.0f hours
", duration.Hours()) // 36 hours
}Database Timestamps β MySQL, PostgreSQL, SQLite
Each database has its own functions for working with Unix timestamps. Store timestamps as integers (INT or BIGINT) when you want fast arithmetic, or as TIMESTAMP WITH TIME ZONE for richer date operations.
MySQL
-- Current timestamp (seconds)
SELECT UNIX_TIMESTAMP(); -- e.g. 1709049600
-- Timestamp to human-readable date
SELECT FROM_UNIXTIME(1709049600); -- 2024-02-27 12:00:00
SELECT FROM_UNIXTIME(1709049600, '%Y-%m-%d'); -- 2024-02-27
-- Date string to Unix timestamp
SELECT UNIX_TIMESTAMP('2024-02-27 12:00:00'); -- 1709049600
-- Rows within the last 30 days (using integer column 'created_at')
SELECT * FROM events WHERE created_at > UNIX_TIMESTAMP() - 30 * 86400;
-- Add 7 days using timestamps
SELECT FROM_UNIXTIME(1709049600 + 7 * 86400); -- 2024-03-05 12:00:00PostgreSQL
-- Current Unix timestamp (seconds, as float)
SELECT EXTRACT(EPOCH FROM NOW()); -- 1709049600.0
-- Integer version
SELECT FLOOR(EXTRACT(EPOCH FROM NOW()))::BIGINT;
-- Timestamp column to Unix seconds
SELECT EXTRACT(EPOCH FROM created_at) FROM events;
-- Unix seconds to timestamptz
SELECT TO_TIMESTAMP(1709049600); -- 2024-02-27 12:00:00+00
-- Current time as Unix integer
SELECT UNIX_TIMESTAMP; -- PostgreSQL 16+
-- Or:
SELECT (EXTRACT(EPOCH FROM now()))::BIGINT;
-- Last 30 days (using timestamptz column)
SELECT * FROM events
WHERE created_at > NOW() - INTERVAL '30 days';
-- Last 30 days (using integer unix column)
SELECT * FROM events
WHERE unix_ts > FLOOR(EXTRACT(EPOCH FROM NOW()))::BIGINT - 30 * 86400;SQLite
-- Current Unix timestamp
SELECT strftime('%s', 'now'); -- e.g. 1709049600
-- Unix timestamp to ISO 8601 string
SELECT datetime(1709049600, 'unixepoch'); -- 2024-02-27 12:00:00
SELECT datetime(1709049600, 'unixepoch', 'localtime'); -- local time
-- Date string to Unix timestamp
SELECT strftime('%s', '2024-02-27 12:00:00');
-- Records from the last 7 days (unix integer column)
SELECT * FROM logs WHERE created_at > strftime('%s', 'now') - 7 * 86400;Notable Epoch Timestamps Reference
These are commonly referenced Unix timestamps that have cultural or technical significance:
| Unix Timestamp | Human Date (UTC) | Significance |
|---|---|---|
0 | 1970-01-01 00:00:00 | The Unix Epoch β the beginning of time for Unix |
1,000,000,000 | 2001-09-09 01:46:40 | Unix billennium β celebrated by programmers worldwide |
1,234,567,890 | 2009-02-13 23:31:30 | Famous sequential timestamp milestone |
1,500,000,000 | 2017-07-14 02:40:00 | 1.5 billion seconds milestone |
2,000,000,000 | 2033-05-18 03:33:20 | 2 billion seconds milestone |
2,147,483,647 | 2038-01-19 03:14:07 | Max 32-bit signed integer β Y2K38 overflow point |
The Y2K38 Problem β The Next Big Date Bug
On January 19, 2038, at 03:14:07 UTC, 32-bit signed integers used to store Unix timestamps will overflow. The value will wrap from 2,147,483,647 (the maximum 32-bit signed integer) to -2,147,483,648 β a negative number representing December 13, 1901. This is analogous to the Y2K bug.
Affected systems:
- Embedded Linux systems using 32-bit
time_t(e.g., older IoT devices, industrial controllers) - MySQL TIMESTAMP columns (limited to 2038-01-19; use DATETIME instead for dates beyond that)
- 32-bit PHP installations with 32-bit integers
- Some legacy C/C++ code using
intfor timestamps - Old file systems that store modification times as 32-bit integers
Already safe (64-bit timestamps):
- Python β uses 64-bit floats internally, safe far beyond 2038
- Go β
time.Timeuses 64-bit internally, handles dates up to year 292 billion - JavaScript β uses 64-bit IEEE 754 floats, safe until year 275,760
- PostgreSQL TIMESTAMPTZ β 64-bit, safe until year 294,276
- 64-bit Linux β
time_tis 64-bit on 64-bit systems
Fix: Always Use 64-bit Integer Columns
-- MySQL: avoid TIMESTAMP (32-bit), use BIGINT or DATETIME
-- BAD (overflows 2038):
CREATE TABLE events (created_at TIMESTAMP);
-- GOOD (64-bit, safe):
CREATE TABLE events (created_at BIGINT UNSIGNED);
-- Or:
CREATE TABLE events (created_at DATETIME); -- supports up to 9999-12-31
-- PostgreSQL: TIMESTAMPTZ is already 64-bit β no changes needed
CREATE TABLE events (created_at TIMESTAMPTZ DEFAULT NOW());Common Mistakes and How to Avoid Them
These are the most frequently encountered timestamp bugs in production code:
1. Forgetting to Multiply by 1000 in JavaScript
const ts = 1709049600; // Unix seconds from an API
// WRONG β new Date() expects milliseconds, produces year 1970!
const wrong = new Date(ts);
console.log(wrong.toISOString()); // "1970-01-20T18:44:09.600Z" β WRONG!
// CORRECT β multiply by 1000
const correct = new Date(ts * 1000);
console.log(correct.toISOString()); // "2024-02-27T12:00:00.000Z" β correct2. Comparing Timestamps from Different Systems with Different Precisions
// API returns seconds, your DB stores milliseconds
const apiTimestamp = 1709049600; // seconds
const dbTimestamp = 1709049600000; // milliseconds
// WRONG β direct comparison is always false!
if (apiTimestamp === dbTimestamp) { ... } // never true
// CORRECT β normalize to the same unit first
const normalize = ts => ts > 1e10 ? Math.floor(ts / 1000) : ts;
if (normalize(apiTimestamp) === normalize(dbTimestamp)) { ... } // true3. Storing Timestamps as Strings Instead of Integers
// WRONG β string storage: slow sorting, no arithmetic, locale-dependent
-- MySQL:
CREATE TABLE events (created_at VARCHAR(20)); -- stores "2024-02-27 12:00:00"
-- CORRECT β integer storage: fast, sortable, arithmetic-friendly
CREATE TABLE events (created_at BIGINT UNSIGNED NOT NULL);
-- ALSO CORRECT β native datetime type
CREATE TABLE events (created_at TIMESTAMPTZ NOT NULL DEFAULT NOW());4. Using Local Time When You Mean UTC
# Python gotcha β datetime(2024, 1, 15) is LOCAL, not UTC
import calendar
from datetime import datetime, timezone
# WRONG β interprets date as local time (depends on server timezone)
wrong = int(datetime(2024, 1, 15).timestamp())
# CORRECT β explicitly UTC
correct = int(datetime(2024, 1, 15, tzinfo=timezone.utc).timestamp())
print(correct) # 1705276800 β always the same regardless of server timezone5. Using 32-bit Integer Columns for Future Dates
-- MySQL TIMESTAMP column max is 2038-01-19 β don't use for subscription expiry, etc.
-- WRONG for long-term dates:
CREATE TABLE subscriptions (expires_at TIMESTAMP);
-- CORRECT:
CREATE TABLE subscriptions (
expires_at DATETIME, -- or BIGINT for Unix seconds
expires_ts BIGINT UNSIGNED -- Unix seconds, 64-bit safe
);Key Takeaways
- Unix timestamps count seconds since 1970-01-01 00:00:00 UTC β always timezone-neutral.
- JavaScript uses milliseconds natively (
Date.now()) β always multiply by 1000 when passing tonew Date()if you have Unix seconds. - Python:
time.time()for seconds (float),datetime.fromtimestamp(ts, tz=timezone.utc)for safe UTC conversion. - Go:
time.Now().Unix()for seconds,time.Unix(ts, 0)to convert back β all 64-bit safe. - Detect ms vs s: if
ts > 1e10, it's milliseconds β divide by 1000 to normalize. - Always store UTC; convert to local time only at display time using the user's timezone preference.
- Use 64-bit columns in databases β MySQL TIMESTAMP overflows in 2038, use DATETIME or BIGINT instead.
- Y2K38 affects 32-bit systems β modern languages and 64-bit databases are already safe.
- Use our free Unix Timestamp Converter for quick online conversions.