What Is a Unix Timestamp?
A Unix timestamp (also called epoch time) is the number of seconds since January 1, 1970 00:00:00 UTC. This "epoch" was chosen somewhat arbitrarily when Unix was designed.
1730000000 โ 2024-10-27 07:33:20 UTC
0 โ 1970-01-01 00:00:00 UTC
-86400 โ 1969-12-31 00:00:00 UTC (negative timestamps are valid)
Unix timestamps are timezone-agnostic โ they always represent a point in time in UTC. This makes them ideal for storing, comparing, and transmitting time values across systems.
Milliseconds vs Seconds
JavaScript uses milliseconds since epoch. Most other languages and systems use seconds. This is the source of countless bugs.
Date.now() // 1730000000000 (milliseconds)
Math.floor(Date.now() / 1000) // 1730000000 (seconds)
new Date(1730000000) // 1970-01-21... (WRONG โ treated as ms)
new Date(1730000000 * 1000) // 2024-10-27... (correct)
new Date(1730000000000) // 2024-10-27... (also correct)
Quick check: If a timestamp is 13 digits, it's milliseconds. If 10 digits, it's seconds.
ISO 8601 Format
ISO 8601 is the international standard for date/time strings:
2024-10-27T07:33:20Z UTC (Z = Zulu = UTC)
2024-10-27T07:33:20+00:00 UTC with explicit offset
2024-10-27T10:33:20+03:00 UTC+3 (same moment)
2024-10-27 Date only
2024-10-27T10:33:20.123Z With milliseconds
Always use ISO 8601 for:
- API request/response bodies
- Log timestamps
- Database string columns (if not using a native datetime type)
- User-facing dates where precision and timezone matter
Avoid locale-specific formats in APIs: 10/27/2024 is ambiguous (MM/DD or DD/MM?).
UTC vs Local Time
The golden rule of server-side development:
Store and compare in UTC. Display in local time.
// โ
Store in UTC
const createdAt = new Date().toISOString(); // "2024-10-27T07:33:20.000Z"
// โ
Display in user's timezone
const display = new Intl.DateTimeFormat("en-US", {
timeZone: "America/New_York",
dateStyle: "full",
timeStyle: "short",
}).format(new Date(createdAt));
// "Sunday, October 27, 2024 at 3:33 AM"
Daylight Saving Time Pitfalls
DST is responsible for more date/time bugs than anything else. Key rules:
- Don't store local times โ store UTC
- Don't add 86400 seconds to get "tomorrow" โ on DST transition days, a day can be 23 or 25 hours
- Don't assume timezones have fixed offsets โ
America/New_Yorkis UTC-5 in winter and UTC-4 in summer - Don't compare times without timezone context
// โ Wrong: assumes a day is always 86400 seconds
const tomorrow = now + 86400;
// โ
Correct: use a proper library
import { add } from "date-fns";
const tomorrow = add(now, { days: 1 });
// date-fns handles DST transitions correctly
The Year 2038 Problem
Unix timestamps stored as a 32-bit signed integer overflow on January 19, 2038 at 03:14:07 UTC. After that, the value wraps to a large negative number representing 1901.
Most modern systems use 64-bit integers for timestamps, making this a non-issue. But embedded systems, legacy databases, and old applications may still use 32-bit storage.
Working with Dates in JavaScript
Modern approach: Temporal (TC39 proposal, landing in 2025)
// Temporal is the modern replacement for Date
const now = Temporal.Now.instant();
const zonedNow = Temporal.Now.zonedDateTimeISO("America/New_York");
const tomorrow = zonedNow.add({ days: 1 });
const diff = laterDate.since(earlierDate, { largestUnit: "hours" });
Current approach: date-fns or dayjs
import { format, add, differenceInDays, parseISO } from "date-fns";
import { formatInTimeZone } from "date-fns-tz";
const date = parseISO("2024-10-27T07:33:20Z");
format(date, "MMM d, yyyy"); // "Oct 27, 2024"
formatInTimeZone(date, "America/New_York", "h:mm a zzz"); // "3:33 AM EDT"
add(date, { days: 7, hours: 2 }); // one week and 2 hours later
differenceInDays(endDate, startDate); // integer days between
Unix timestamp conversions
// Current timestamp
const nowSeconds = Math.floor(Date.now() / 1000);
const nowMs = Date.now();
// From timestamp
const date = new Date(1730000000 * 1000); // seconds โ ms
const dateFromMs = new Date(1730000000000); // ms directly
// To timestamp
const ts = Math.floor(date.getTime() / 1000); // โ seconds
Working with Dates in Python
from datetime import datetime, timezone, timedelta
# Current UTC time
now = datetime.now(timezone.utc)
# From Unix timestamp
dt = datetime.fromtimestamp(1730000000, tz=timezone.utc)
# To Unix timestamp
ts = int(dt.timestamp())
# ISO 8601 format
iso = dt.isoformat() # "2024-10-27T07:33:20+00:00"
dt2 = datetime.fromisoformat("2024-10-27T07:33:20+00:00")
# Timezones with pytz or zoneinfo (Python 3.9+)
from zoneinfo import ZoneInfo
ny = dt.astimezone(ZoneInfo("America/New_York"))
Working with Dates in Go
import "time"
// Current UTC time
now := time.Now().UTC()
// From Unix timestamp
t := time.Unix(1730000000, 0).UTC()
// To Unix timestamp
ts := t.Unix() // seconds
tsMs := t.UnixMilli() // milliseconds
// Format (Go uses a reference time: Mon Jan 2 15:04:05 MST 2006)
formatted := t.Format(time.RFC3339) // "2024-10-27T07:33:20Z"
display := t.In(time.LoadLocation("America/New_York")).
Format("Jan 2, 2006 3:04 PM")
// Parse
parsed, _ := time.Parse(time.RFC3339, "2024-10-27T07:33:20Z")
Database Timestamps
| Database | Recommended Type | Notes |
|---|---|---|
| PostgreSQL | TIMESTAMPTZ | Stores UTC, displays in session timezone |
| MySQL | DATETIME | No timezone support; store in UTC explicitly |
| SQLite | INTEGER | Store Unix epoch seconds |
| MongoDB | Date | Milliseconds since epoch |
Always use TIMESTAMPTZ over TIMESTAMP in PostgreSQL โ the latter ignores timezone information.
Try It: ToolNinja Timestamp Converter
Convert between Unix timestamps and human-readable dates with the ToolNinja Timestamp Converter. Supports seconds and milliseconds, converts to any timezone, shows ISO 8601 format. Runs in your browser.