Unix Timestamp Conversion: Every Format Explained
A Unix timestamp is the number of seconds since 1970-01-01 00:00:00 UTC. Sounds simple. In practice, it is the source of more bugs than any other date representation in software.
Seconds vs milliseconds
The original Unix timestamp counts seconds (10 digits today: 1745020800). JavaScript and many APIs use milliseconds (13 digits: 1745020800000). The "Date" library you're using will pick one — if you mix them, you'll see dates in 1970 (treating ms as seconds) or in the year 50000 (treating seconds as ms).
Quick check: 10 digits = seconds, 13 digits = milliseconds.
Timezones
Unix timestamps are always UTC. The "timezone" is applied when you format them for display. There is no such thing as a "PST timestamp" or "IST timestamp" — those are display formats, not storage formats.
Common bug: server in UTC, client in IST (UTC+5:30). Server stores 1745020800 (which is 2026-04-19 00:00:00 UTC). Client formats it as 2026-04-19 05:30:00 IST. Both are correct; they're the same instant.
ISO 8601: the human-readable cousin
ISO 8601 format: 2026-04-19T00:00:00Z (Z = Zulu = UTC). Equivalent to Unix timestamp 1745020800. Always include the timezone — Z for UTC or +05:30 for offset.
Why ISO 8601 in addition to Unix timestamps?
- Human-readable — no mental conversion needed
- Carries timezone information explicitly
- Sortable lexicographically (2026 < 2027)
- Standard across most APIs and databases
Conversion in different languages
// JavaScriptconstts = Math.floor(Date.now() /1000);// secondsconsttsMs =Date.now();// msconstiso =newDate(ts *1000).toISOString();# Pythonimporttime, datetime ts =int(time.time())# secondsiso = datetime.datetime.fromtimestamp(ts, datetime.timezone.utc).isoformat()// Gots := time.Now().Unix()// secondstsMs := time.Now().UnixMilli()// msiso := time.Now().UTC().Format(time.RFC3339)# Bashdate +%s# secondsdate +%s%3N# msdate -u +"%Y-%m-%dT%H:%M:%SZ"# ISO 8601
The Y2038 problem
32-bit signed integers overflow at 2038-01-19 03:14:07 UTC. After that, a 32-bit Unix timestamp wraps to negative numbers (which represent dates in 1901).
Status in 2026:
- 64-bit systems unaffected (won't overflow until year 292,277,026,596)
- Linux kernel migrated to 64-bit time_t
- Embedded systems (older IoT devices, automotive ECUs) still vulnerable
- Some old database schemas still use INT for timestamps
Action: audit your DB schemas. PostgreSQL timestamptz, MySQL BIGINT for storing as ms.
Microseconds and nanoseconds
- Microseconds (16 digits) — used by Postgres timestamps, Python datetime
- Nanoseconds (19 digits) — used by Go's
time.UnixNano(), eBPF, distributed tracing
Leap seconds
Earth's rotation is irregular, so UTC occasionally adds a leap second. The Unix timestamp standard does not account for leap seconds — the count of seconds in a day is always 86,400 even when reality has 86,401.
Implication: during a leap second, two real-world moments share the same Unix timestamp. For most applications this is invisible. For high-frequency trading, distributed systems, or scientific timing — use TAI (atomic time) or PTP.
Common bugs
- Mixing seconds and milliseconds. Detect: dates in 1970 or year 50000.
- Server in non-UTC timezone. Always run servers in UTC and convert at display time.
- SQL timestamp without timezone. Use
timestamptzin Postgres, store as UTC always. - Daylight saving transitions. Spring-forward day has 23 hours; fall-back has 25. Don't assume "1 day = 86400 seconds" in local time.
- Calling
new Date('2026-01-15'). Without explicit timezone, JavaScript interprets as UTC. With time but no offset, it's local. Always include Z or offset.
Storing timestamps
Best practice in 2026:
- Database:
TIMESTAMPTZin Postgres,BIGINTfor ms-precision in MySQL/SQLite - JSON API: ISO 8601 with timezone (
2026-04-12T07:30:00Z) for human readability, or millisecond Unix timestamp for machine efficiency - Logs: ISO 8601 always — searchable and sortable
- Distributed systems: include monotonic component (UUIDv7, ULID) plus wall-clock timestamp
Display formatting
Convert at the edges (just before display, just after parse). Internally, store and pass UTC.
// Always show user's local timeconstdate =newDate(timestampMs); date.toLocaleString('en-IN', { timeZone:'Asia/Kolkata'});
Tools
- Unix timestamp converter — convert between seconds, ms, ISO, human-readable
- UUIDv7 generator — embeds Unix milliseconds in the ID
Bottom line
Always store UTC. Always include explicit timezone in serialised dates. Be paranoid about seconds vs milliseconds. Audit your databases for 32-bit timestamps. Use ISO 8601 for human-facing APIs.
Try the free dev tools suite
15+ tools. 100% client-side. No signup. No tracking.
Browse all tools →