Unix Timestamp Explained: Epoch Time, Milliseconds, BST and the 2038 Problem
A Unix timestamp counts seconds since 1 January 1970 UTC. Learn seconds vs milliseconds, the 2038 problem, handling BST and time zones, and ISO 8601 dates.
A Unix timestamp is the number of seconds that have passed since midnight UTC on 1 January 1970, a moment known as the Unix epoch. For example, 1792659600 is 09:00 UTC on 22 October 2026, which is 10:00 in the UK because British Summer Time is still in force that day, and 05:00 in New York (EDT). The same timestamp means the same instant everywhere in the world.
Timestamps are everywhere in web development. They appear in databases, server logs, API responses, cookies, JWT expiry claims, analytics exports and automation tools. They're simple, compact and easy to compare, but they cause a steady stream of bugs, from times that are an hour out in summer to dates in 1970 or the year 58,000. This guide explains how they work and how to avoid the common traps.
Make It Flow's free timestamp converter turns any Unix timestamp into a readable date in UTC and UK time, and back again.
Key takeaways
- A Unix timestamp is the number of seconds since 00:00:00 UTC on 1 January 1970, and it's the same everywhere in the world at the same moment.
- 10-digit timestamps are seconds and 13-digit ones are milliseconds; mixing them up is one of the most common date bugs.
- Signed 32-bit timestamps run out at 03:14:07 UTC on 19 January 2038, so older systems and database columns need checking.
- Store and compare times in UTC, convert to local time only for display, and use ISO 8601 with an offset when exchanging dates as text.
What is a Unix timestamp?
Unix time (also called epoch time or POSIX time) is a single number: the count of seconds since 1970-01-01T00:00:00Z.
| Timestamp | Date and time (UTC) |
|---|---|
0 |
1 January 1970, 00:00:00 |
1000000000 |
9 September 2001, 01:46:40 |
1792659600 |
22 October 2026, 09:00:00 |
2147483647 |
19 January 2038, 03:14:07 |
-86400 |
31 December 1969, 00:00:00 |
Negative values represent dates before 1970, although not every system supports them.
Why developers like timestamps
- No time zone ambiguity. A timestamp refers to one exact instant. "14:00" alone doesn't.
- Easy maths. Add 3,600 for an hour or 86,400 for a day. Subtract two timestamps to get a duration in seconds.
- Easy sorting and comparison. A larger number is always later.
- Compact. A single integer, typically stored in 4 or 8 bytes.
What about leap seconds?
Unix time ignores leap seconds. Every day is treated as exactly 86,400 seconds. For almost all business software that makes no practical difference. It matters only in specialist fields such as astronomy, satellite navigation and high-frequency trading.
Seconds vs milliseconds
This is the most common timestamp bug. Different languages count in different units:
| Language / system | Default unit | Example call |
|---|---|---|
Unix / Linux (date +%s) |
Seconds | date +%s |
| PHP | Seconds | time() |
| Python | Seconds (as a float) | time.time() |
| MySQL | Seconds | UNIX_TIMESTAMP() |
JWT exp, iat, nbf |
Seconds | (set by your library) |
| JavaScript | Milliseconds | Date.now() |
| Java | Milliseconds | System.currentTimeMillis() |
MDN confirms that JavaScript's Date.now() returns milliseconds since the epoch.
How to tell them apart
For current dates:
- 10 digits (for example
1792659600): seconds - 13 digits (for example
1792659600000): milliseconds - 16 digits: microseconds, which some databases and logging tools use
- 19 digits: nanoseconds
What goes wrong
- A seconds value passed to JavaScript's
new Date()lands in January 1970, because it's read as milliseconds. - A milliseconds value treated as seconds lands tens of thousands of years in the future.
- A JWT whose
expis set in milliseconds by mistake effectively never expires. That's a real security problem, covered in our guide to what a JWT is.
// Seconds -> JavaScript Date
const d = new Date(1792659600 * 1000);
// JavaScript Date -> seconds
const seconds = Math.floor(Date.now() / 1000);
Time zones, BST and why you should store UTC
A Unix timestamp has no time zone, because it's always counted from UTC. Time zones only come into play when you turn it into a human-readable date.
How UK time works
The UK uses Greenwich Mean Time (GMT, equal to UTC) in winter and British Summer Time (BST, UTC+1) in summer. According to GOV.UK, the clocks go forward one hour at 1am on the last Sunday in March and back one hour at 2am on the last Sunday in October. The US and Canada switch on different dates (the second Sunday in March and the first Sunday in November), which is one more reason to rely on named time zones:
| Year | Clocks go forward | Clocks go back |
|---|---|---|
| 2026 | 29 March | 25 October |
| 2027 | 28 March | 31 October |
Bugs caused by BST
- Times an hour out in summer. Code that assumes UK time always equals UTC is right for five months of the year and wrong for seven.
- The missing hour. On the day the clocks go forward, 01:00 to 01:59 UK time doesn't exist. A job scheduled for 01:30 may not run at all.
- The repeated hour. On the day the clocks go back, 01:00 to 01:59 happens twice. A job may run twice, or log entries may appear out of order.
- Wrong day boundaries. A daily report that splits at midnight UTC will put late-evening UK orders on the following day all summer.
The rule of thumb
- Store times as UTC, either as Unix timestamps or as UTC datetime values.
- Calculate in UTC.
- Convert to the user's time zone (for example
Europe/LondonorAmerica/New_York) only when displaying. - Use named time zones, such as
Europe/London, not fixed offsets like+01:00, when you need to convert future dates. Named zones know when BST starts and ends. A fixed offset doesn't. - Schedule recurring jobs in UTC, or use a scheduler that handles daylight saving properly.
new Date(1792659600 * 1000).toLocaleString('en-GB', { timeZone: 'Europe/London' });
// "22/10/2026, 10:00:00"
ISO 8601: the text alternative
When dates need to be readable by humans, or exchanged as text in JSON, CSV files or APIs, use ISO 8601 format. The internet profile of it is RFC 3339:
2026-10-22T09:00:00Z (UTC, "Z" means zero offset)
2026-10-22T10:00:00+01:00 (the same instant, written in BST)
2026-10-22 (a date only)
| Unix timestamp | ISO 8601 / RFC 3339 | |
|---|---|---|
| Human-readable | No | Yes |
| Time zone | Always UTC | Explicit offset or Z |
| Sorts correctly as text | As a number | Yes, if all values use the same offset |
| Size | Small integer | 20–25 characters |
| Best for | Storage, maths, tokens | APIs, logs, exports, JSON |
Always include the offset or Z. 2026-10-22T09:00:00 without one is ambiguous. Different systems will read it as UTC, as server-local time or as browser-local time.
Avoid ambiguous formats like 10/11/2026. In the UK that's 10 November, but in the US it's 11 October. ISO 8601's year-month-day order removes the doubt. If you're converting spreadsheet exports, our CSV to JSON converter works best when dates are already in ISO format.
ISO 8601 dates also matter for SEO. datePublished and dateModified in your structured data should use them. Check yours with our schema markup validator.
The year 2038 problem
Many older systems store Unix time as a signed 32-bit integer. The largest value that type can hold is 2,147,483,647, which is 03:14:07 UTC on 19 January 2038. One second later, the number overflows and wraps around to a large negative value, which these systems read as December 1901.
It's sometimes called "Y2K38" or the "Epochalypse".
Is it still a risk?
Modern 64-bit operating systems and most current languages already use 64-bit time values, which won't overflow for billions of years. The risk lies in:
- Older embedded devices: routers, CCTV, building systems, industrial controllers and payment terminals
- Database columns defined as 32-bit integers holding timestamps
- MySQL's
TIMESTAMPtype, which has historically been limited to dates up to 2038 (DATETIMEdoesn't have that limit) - File formats and protocols with a fixed 32-bit time field
- Old compiled software that is no longer updated
The deadline is closer than it looks for anything dealing with future dates. A 15-year mortgage, a long lease or a certificate expiry calculated today can already reach past 2038.
What to check
- Search your database schema for timestamp columns stored as
INT(32-bit). Migrate them toBIGINTor a proper datetime type. - Check whether
TIMESTAMPcolumns need to hold dates after January 2038. - Ask suppliers of long-lived hardware whether their firmware is 2038-safe.
- Test date handling with a value past
2147483647.
Getting the current Unix timestamp
| Where | Command |
|---|---|
| Linux / macOS terminal | date +%s |
| JavaScript | Math.floor(Date.now() / 1000) |
| PHP | time() |
| Python | int(time.time()) |
| MySQL | SELECT UNIX_TIMESTAMP(); |
| PostgreSQL | SELECT EXTRACT(EPOCH FROM now()); |
| Browser | Our timestamp converter shows the live value |
Timestamp debugging checklist
- Count the digits: 10 means seconds, 13 means milliseconds.
- Check whether the source system stores UTC or local time.
- If a time is exactly one hour out, suspect BST.
- If the date is in 1970, a seconds value was probably read as milliseconds.
- If the date is in the far future, milliseconds were probably read as seconds.
- Make sure every ISO date string carries
Zor an offset. - Check that the server clock is synchronised with NTP, because drifting clocks break token expiry and TLS checks.
When your timestamps come from HTTP responses, such as Last-Modified, Expires or cookie dates, our guide to browser caching and Cache-Control explains how those headers use dates. More handy converters are on our free tools for web development page.
FAQ
What is a Unix timestamp?
A Unix timestamp is the number of seconds since 00:00:00 UTC on 1 January 1970, the Unix epoch. It identifies a single moment in time regardless of time zone. That makes it a convenient way to store, compare and calculate with dates in software, databases, logs and APIs.
How do I convert a Unix timestamp to a date?
Use a converter such as our free timestamp converter, or code. In JavaScript, use new Date(seconds * 1000). In PHP, use date('Y-m-d H:i:s', $ts). In Python, use datetime.fromtimestamp(ts, tz=timezone.utc). Remember to multiply by 1,000 in JavaScript, and choose the time zone you want to display.
Is a Unix timestamp in seconds or milliseconds?
Strictly, Unix time is in seconds, but JavaScript, Java and some APIs use milliseconds. For present-day dates, a 10-digit number is seconds and a 13-digit number is milliseconds. Mixing them up produces dates in 1970 or far in the future, so always check which unit a system expects.
Does a Unix timestamp change with British Summer Time?
No. A Unix timestamp is always based on UTC, so it's unaffected by BST or any other time zone. Only the conversion to a local, human-readable time changes. In summer, UK clock time is UTC+1, so the same timestamp displays one hour later than it would in GMT.
What is the year 2038 problem?
Systems that store Unix time as a signed 32-bit integer can only count up to 2,147,483,647, which is 03:14:07 UTC on 19 January 2038. After that the value overflows and wraps to 1901. Modern 64-bit systems are unaffected, but older devices, databases and file formats may still need fixing.
Should I store dates as timestamps or ISO 8601 strings?
For storage and calculation, a Unix timestamp or a database datetime column in UTC is efficient and unambiguous. For APIs, logs, exports and anything people read, ISO 8601 with a Z or an offset is clearer. Many systems store UTC internally and use ISO 8601 at the edges.
Related reading
- Regex Cheat Sheet: JavaScript Regular Expressions With UK and US Examples: JavaScript regex cheat sheet: character classes, quantifiers, groups, lookarounds, flags, UK postcode, US ZIP and phone patterns, and avoiding backtracking.
- UUID v4 vs v7: Which Should You Use for Database IDs?: UUID v4 vs v7 explained: how RFC 9562 defines each, why time-ordered v7 IDs suit database indexes, the collision odds, and when v4 is still the better pick.
- Cron Expression Explained: Syntax, Examples and Common Mistakes: Cron expressions explained: the five fields, ranges, lists and steps, ready-made examples, time zone and daylight saving traps, and how GitHub Actions differs.
More guides for your industry
Free checklist (PDF)
Free web developers website checklist
31 practical checks for web developers: website speed and mobile, Google Business Profile and reviews, email security, booking and enquiry handling, and AI search visibility. Each one says why it matters, and many link to a free tool that checks it.
Written by the MakeItFlow team
We build the website audit these guides are based on. Every fact is checked against the primary sources listed above and this guide was last reviewed on 27 October 2026 . How we research and check
Check your own site in 30 seconds
Run a free audit covering speed, SEO, DNS, email authentication and security headers — and get a prioritised fix list.