Unix timestamps explained - epoch, ISO-8601, and timezones
Unix timestamps encode time as a plain integer - seconds (10 digits) or milliseconds (13 digits) since 1 January 1970 UTC. ISO 8601 and RFC 2822 add timezone-aware human-readable strings for data interchange and email headers. This guide explains how to convert between all three formats, avoid the common off-by-1000 pitfall, and handle DST transitions correctly when displaying local times.
Unix epoch: seconds since 1970-01-01 UTC
The Unix timestamp - also called "epoch time" - is the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970. That reference point is arbitrary but universal; every Unix-derived system (Linux, macOS, Android, iOS) and almost every programming language tracks time internally as a count from this moment.
A current-ish value: 1776495426 translates to 2026-04-18 12:17:06 UTC. There's no timezone encoded in the number itself - it's always UTC - which is both a strength (no ambiguity when two systems compare timestamps) and a trap (whatever converts the number to a human-readable string has to pick a timezone, and it usually picks the local one).
Seconds vs milliseconds: the first source of confusion
JavaScript, Java, and most modern language standard libraries default to milliseconds since the epoch, not seconds. That same moment - 2026-04-18 12:17:06 UTC - is 1776495426 in seconds (10 digits) but 1776495426000 in milliseconds (13 digits). A quick rule of thumb for sanity-checking a timestamp you received:
- 10 digits → seconds (Unix command line, PHP, Python
time.time(), Go). - 13 digits → milliseconds (JavaScript
Date.now(), JavaSystem.currentTimeMillis(), most JSON APIs). - 16 or 19 digits → microseconds or nanoseconds (specialized telemetry and scientific timing).
| Precision | Digits | Typical value (2026) | Maximum year (64-bit) |
|---|---|---|---|
| Seconds | 10 | 1,776,495,426 | Far future (2038 for 32-bit signed) |
| Milliseconds | 13 | 1,776,495,426,000 | 292,278,994 AD |
| Microseconds | 16 | 1,776,495,426,000,000 | Specialized telemetry |
A 10-digit seconds value interpreted as milliseconds renders as a date in 1970 (50+ years too early). A 13-digit millisecond value interpreted as seconds renders as a date ~56,000 AD. Both errors are instantly visible once the timestamp is converted - use Convert Milliseconds to Date to sanity-check, or Convert a Date to Milliseconds to go the other direction.
ISO 8601: the readable interchange format
ISO 8601 is a human-readable date-time format that also machines agree on. The canonical form looks like: 2026-04-18T12:17:06.520Z. Parts:
- Date:
2026-04-18(YYYY-MM-DD, always this order). - Separator:
T(literal letter T between date and time). - Time:
12:17:06.520(HH:MM:SS.sss, 24-hour). - Timezone:
Zfor UTC, or an offset like+07:00/-05:30for other zones.
ISO 8601 is unambiguous (no regional date confusion like 04-18 vs 18-04), sortable as a plain string (lexical order matches chronological order when the timezone is the same), and supported by every modern parser. If you control the API you're building, prefer ISO 8601 strings over raw Unix epoch numbers - they carry the timezone explicitly, which removes a whole class of bugs.
RFC 2822: the legacy email and HTTP format
RFC 2822 (and the nearly identical HTTP-date from RFC 7231) looks like Sat, 18 Apr 2026 12:17:06 +0000. It's the format you'll see in email Date: headers, HTTP Last-Modified headers, and some older web APIs. It's readable but not sortable as a plain string (the weekday prefix breaks lexical ordering), so systems increasingly return ISO 8601 alongside or instead of RFC 2822. When you need to generate RFC 2822 manually, use a library rather than building the string yourself - the weekday name and month abbreviation are locale-sensitive and easy to get wrong.
UTC vs local time: the root of most timestamp bugs
Unix epoch timestamps are always UTC; ISO 8601 strings can be UTC (Z) or any offset; RFC 2822 almost always carries an offset. But when a programme displays a timestamp, it usually converts to the local timezone of the machine doing the display.
This is fine for a single user but causes chaos in three scenarios:
- Sharing a timestamp in chat. "The deploy happened at 14:00" is ambiguous - whose 14:00? Paste the ISO 8601 value (
2026-04-18T14:00:00+07:00) or explicitly state the timezone. - Logs from multiple servers. Set every server to UTC. Always. Log aggregators and incident-response tooling assume UTC; mixing timezones in logs is the fastest way to misattribute a cause-effect chain.
- User-facing schedules. Store the event time in UTC (or the event's source timezone with explicit offset) and convert at display time. Do not store "7pm" with no timezone; "7pm" in one user's session may be 4pm for another.
Three common pitfalls (and how to catch them)
1. Integer-vs-string timestamps in JSON. JavaScript's JSON.parse will faithfully produce a number for 1776495426520 - but if the API returned the same timestamp as a string "1776495426520", any downstream code doing arithmetic on it will silently coerce. Always check the type before passing to new Date().
2. Month 0-11 in JavaScript Date. new Date(2026, 3, 18) is 18 April 2026, not 18 March 2026. Month is 0-indexed but day and year are 1-indexed. Prefer the ISO 8601 constructor (new Date("2026-04-18")) which follows the natural numbering.
3. DST transitions. On "spring forward" night, 2:30am local doesn't exist; on "fall back" night, 1:30am happens twice. If your system stores local-time strings, these moments create impossible or duplicated timestamps. UTC storage eliminates the problem; Date libraries like Luxon or date-fns-tz handle the conversion explicitly.
Negative timestamps, leap seconds, and the Year 2038 problem
Three edge cases of the Unix-time standard that rarely come up until they break something. First, the count can go negative: any moment before 1 January 1970 UTC is a negative integer, so -86400 is 31 December 1969 00:00:00 UTC, not an error to be filtered out. Second, Unix time deliberately ignores leap seconds - by POSIX convention every calendar day is defined as exactly 86,400 seconds, so the occasional UTC leap second is either dropped or "smeared" across surrounding seconds depending on the operating system, rather than being counted. Third, a timestamp stored as a signed 32-bit integer overflows at 2,147,483,647 seconds after the epoch - 03:14:07 UTC on 19 January 2038 - and wraps around to a large negative number, which most systems then render as a date in December 1901. Modern 64-bit timestamps push that overflow far enough into the future (roughly the year 292,278,994 AD, per the table above) that it is no longer a practical concern, but any code still using a 32-bit epoch field is exposed to the same bug the industry called Y2K, just eighteen years later.
Which converter do I need - date to milliseconds, or milliseconds to date?
Convert a Date to Milliseconds takes the reverse direction from what its name might suggest: you pick a specific calendar date and time in a format-locked datetime box and click Get Millisecond, and the epoch-milliseconds value for that exact moment appears below the button - it does not run as a continuously ticking clock. Convert Milliseconds to Date goes the other way: paste a millisecond epoch value and the matching calendar date and time appear on the same screen. That page also arrives pre-filled with the current moment's epoch value and auto-runs the conversion the instant it loads, so the first thing visible is a working example of the exact input format expected, before a single character has been typed. Both converters run the arithmetic entirely in the browser - no upload, no account, and no value leaves the device.
Related tools
- Convert Milliseconds to Date - paste a timestamp, get UTC and local formatted dates.
- Convert a Date to Milliseconds - pick a datetime, get its epoch-milliseconds value.
- MD5 Converter - hash a string for checksums or de-duplication keys.
- JSON Parser - inspect API responses that contain timestamp fields.
- Current millis - live Unix timestamp in milliseconds - a companion guide showing how to read the live epoch value and what the digit count means.
- Is this long number a millisecond or second timestamp? - use this when you receive an unfamiliar number and need to confirm its precision before parsing.
Frequently Asked Questions
Can a Unix timestamp be negative?
Yes. Any date before 1 January 1970 UTC is represented as a negative integer - for example, -86400 is 31 December 1969 00:00:00 UTC, exactly one day before the epoch. A negative value is a valid pre-1970 date, not an error.
Do leap seconds get added into a Unix timestamp?
No. By POSIX convention every day is defined as exactly 86,400 seconds, so leap seconds are excluded from the count rather than added to it. Systems that need to stay aligned with UTC handle the occasional leap second by dropping it or smearing it across nearby seconds, never by counting it in the epoch value itself.
What happens when a 32-bit Unix timestamp overflows?
It hits the "Year 2038 problem": a signed 32-bit integer runs out of room at 03:14:07 UTC on 19 January 2038 (2,147,483,647 seconds after the epoch) and wraps around to a large negative number, which typically renders as a date in December 1901. 64-bit timestamps do not have this problem within any realistic timeframe.
Does "Z" mean something different from "+00:00" in an ISO 8601 timestamp?
No. Both represent UTC. "Z" (sometimes called "Zulu time") is simply shorthand for a zero offset, so 2026-04-18T12:17:06Z and 2026-04-18T12:17:06+00:00 describe the exact same moment.
Is "Convert a Date to Milliseconds" a live, continuously updating clock?
No. It converts one specific datetime you pick in the input box into its epoch-milliseconds value when you click the button - it is a one-shot conversion, not a running clock.
Does "Convert Milliseconds to Date" show a working example before I paste my own value?
Yes. The page loads pre-filled with the current moment's millisecond epoch and immediately runs the conversion, so a live example is already on screen in the exact format the box expects, before any typing happens.
Why trust these tools
- Ten-plus years of web tooling. The freetoolonline editorial team has shipped browser-based utilities since 2015. The goal has never changed: get you to a working output fast, without an install.
- No install, no sign-up. Open a tool and get a working output in seconds - nothing to download and no account to create. Tools that need heavy processing run it on our service, so even a low-powered machine gets the job done.
- Analytics stops at the page view. We measure which pages get visited, not what you type or upload inside a tool. There is nothing to sign in to and no profile is attached to your input.
- Open-source core components. The processing engines underneath (libheif, libde265, pdf-lib, terser, clean-css, ffmpeg.wasm, and others) are public and audit-able. We link to each one in its tool page's footer.
- Free, with or without ads. All tools are fully functional without sign-up. The Disable Ads button in the header is always available if you need a distraction-free run.