Time

Unix Timestamps Explained — Format, Seconds vs Milliseconds & UTC

What a Unix timestamp is, how the format works, seconds vs milliseconds, the trailing Z, and converting to and from human dates.

HandyUtils January 1, 2026 10 min read

Unix timestamps are the foundation of time handling in computing. Simple yet powerful, understanding them is essential for any developer working with dates and times.

What is a Unix Timestamp?

A Unix timestamp (also called Epoch time or POSIX time) is the number of seconds that have elapsed since January 1, 1970, at 00:00:00 UTC—the Unix Epoch.

Unix Timestamp: 1705312800
Represents:     January 15, 2024, at 10:00:00 UTC

That's it—just a number counting seconds. No timezones, no date formats, no ambiguity. Because the value is a single integer, it means the exact same instant on every machine on the planet; only the way you format it for a human changes from place to place.

The Unix Epoch

The Epoch is the reference point:

January 1, 1970, 00:00:00 UTC = 0

Why 1970? It was chosen when Unix was being developed in the early 1970s. A recent date meant smaller numbers, and it was already in the past (no negative values for current times). Timestamps before 1970 are simply negative numbers.

Some notable timestamps:

Timestamp Date Event
0 Jan 1, 1970 Unix Epoch
1000000000 Sep 9, 2001 "Unix Billennium"
1234567890 Feb 13, 2009 Memorable number
1672531200 Jan 1, 2023 Start of 2023 (UTC)
2000000000 May 18, 2033 Two billion
2147483647 Jan 19, 2038 Y2K38 problem

Curious about the numbers you keep seeing hard-coded in tests and configs? See our companion reference, Notable Unix Timestamps, for the story behind each one.

Seconds vs Milliseconds

This is the single most common source of "my date is in 1970" or "my date is in the year 55000" bugs. Unix time is officially measured in seconds since the epoch, but many environments—JavaScript most notably—work in milliseconds.

// Seconds (10 digits for current dates)
1705312800

// Milliseconds (13 digits for current dates)
1705312800000

How to tell them apart: count the digits. For any date in the current era (roughly 2001 through 2286):

Digits Unit Example
10 Seconds 1705312800
13 Milliseconds 1705312800000
16 Microseconds 1705312800000000
19 Nanoseconds 1705312800000000000

JavaScript's Date.now() and getTime() return milliseconds; most other languages and Unix system calls return seconds.

// JavaScript — milliseconds
Date.now()              // 1705312800000

// Python — seconds (with a fractional part)
import time
time.time()             // 1705312800.123

Converting between the two is just multiply or divide by 1000:

// Seconds  -> milliseconds
const ms = seconds * 1000;

// Milliseconds -> seconds (round down to a whole second)
const seconds = Math.floor(ms / 1000);

A reliable rule of thumb: if you feed a value into a date library and land on January 1970, you passed seconds where milliseconds were expected (too small by 1000×). If you land thousands of years in the future, you passed milliseconds where seconds were expected.

What the Trailing Z Means

When you see an ISO 8601 timestamp like 2024-01-15T10:00:00Z, that trailing Z is not a typo or a placeholder—it stands for Zulu time, the military and aviation name for UTC (Coordinated Universal Time). It means "zero offset from UTC."

2024-01-15T10:00:00Z         <- UTC, exactly
2024-01-15T10:00:00+00:00    <- identical meaning, written out
2024-01-15T11:00:00+01:00    <- same instant, expressed in a +1 zone

So Z is shorthand for +00:00. All three lines above can describe the same moment; the third just formats it for an observer one hour ahead of UTC.

A timestamp without a Z or an explicit offset (for example 2024-01-15T10:00:00) has no timezone information at all. It is ambiguous—different systems may assume UTC, may assume local time, or may reject it. Whenever you emit an ISO string for storage or an API, include the Z (or an explicit offset) so the value is unambiguous.

Unix Time vs ISO 8601

Both represent the same underlying instant; they trade off machine-friendliness against human-readability.

Unix timestamp ISO 8601
Example 1705312800 2024-01-15T10:00:00Z
Human-readable No Yes
Timezone shown Always UTC (implicit) Explicit (Z or offset)
Best for Storage, math, comparisons, APIs Logs, display, config, debugging
Sortable as text Yes (fixed width) Yes (if same format)
Size ~4-8 bytes as an integer 20+ bytes as a string

The two are trivially interchangeable:

// Unix seconds -> ISO 8601
new Date(1705312800 * 1000).toISOString();
// "2024-01-15T10:00:00.000Z"

// ISO 8601 -> Unix seconds
Math.floor(new Date('2024-01-15T10:00:00Z').getTime() / 1000);
// 1705312800

Many APIs happily provide both so neither the machine nor the human has to do the conversion:

{
  "created_at": 1705312800,
  "created_at_iso": "2024-01-15T10:00:00Z"
}

Timezones and UTC

A Unix timestamp is always UTC. There is no such thing as a "New York timestamp"—1705312800 is the same instant whether you're in Tokyo, London, or Los Angeles. The timezone only enters the picture when you format the number for a human.

const timestamp = 1705312800;
const date = new Date(timestamp * 1000);

// UTC
date.toUTCString();   // "Mon, 15 Jan 2024 10:00:00 GMT"

// Local time (depends on the viewer's timezone)
date.toString();      // "Mon Jan 15 2024 05:00:00 GMT-0500 (EST)"

Both lines describe the same moment; only the presentation differs. This is why timestamps are so convenient for storage—you never have to record a timezone alongside them.

Best Practices

  1. Store in UTC: timestamps are inherently UTC—store the raw number.
  2. Convert on display: render times in the viewer's local timezone at the last possible moment.
  3. Accept with a timezone: when receiving times, require an explicit offset (or a trailing Z), or clearly document that bare values are treated as UTC.
import time
from datetime import datetime

# Storing
created_at = int(time.time())            # UTC timestamp

# Displaying
local_time = datetime.fromtimestamp(created_at, tz=user_timezone)

Why Timestamps Are Useful

1. Language/System Agnostic

Every language can work with integers:

// JavaScript
new Date(1705312800 * 1000)

// Python
datetime.fromtimestamp(1705312800)

// SQL
FROM_UNIXTIME(1705312800)

2. Easy Date Math

Adding and subtracting time is just arithmetic:

const now = 1705312800;
const oneHourLater = now + 3600;      // Add 3600 seconds
const oneDayAgo = now - 86400;        // Subtract 86400 seconds
const oneWeekLater = now + 604800;    // 7 * 24 * 60 * 60

3. Easy Comparison and Sorting

if (timestamp1 < timestamp2) {
    // timestamp1 is earlier
}

Because they're plain integers, timestamps sort chronologically automatically—no locale-aware string parsing required.

4. Storage Efficient

An integer takes less space than a date string:

  • Timestamp: 4 bytes (32-bit) or 8 bytes (64-bit)
  • ISO 8601 string: 20+ bytes

Converting Timestamps to Dates

JavaScript

// Timestamp to Date
const date = new Date(1705312800 * 1000);  // Note: multiply by 1000
console.log(date.toISOString());  // "2024-01-15T10:00:00.000Z"

// Date to timestamp
const timestamp = Math.floor(Date.now() / 1000);  // Divide by 1000 for seconds

Python

from datetime import datetime, timezone

# Timestamp to Date
date = datetime.fromtimestamp(1705312800, tz=timezone.utc)  # UTC

# Date to timestamp
timestamp = int(datetime.now(tz=timezone.utc).timestamp())

Unix/Linux Command Line

# Current timestamp
date +%s

# Timestamp to date
date -d @1705312800

# Date to timestamp
date -d "2024-01-15 10:00:00" +%s

The Year 2038 Problem (32-bit vs 64-bit)

For decades, many systems stored Unix time in a signed 32-bit integer. A signed 32-bit value can count up to 2,147,483,647—and that ceiling arrives sooner than you'd think.

Maximum 32-bit timestamp: 2147483647
Represents: January 19, 2038, at 03:14:07 UTC

One second later, the counter overflows and wraps around to the most negative value, which a 32-bit system interprets as December 13, 1901. This is the Year 2038 problem (sometimes "Y2K38")—the same class of bug as Y2K, but rooted in integer size rather than two-digit years.

Who's Affected?

  • Embedded systems and IoT devices with long service lives
  • Legacy 32-bit software and firmware
  • Databases with 32-bit timestamp columns
  • Old programming-language runtimes

The Fix: 64-bit

Modern systems store time in a signed 64-bit integer, which pushes the overflow roughly 292 billion years into the future—longer than the age of the universe.

// Old (32-bit problem)
time_t timestamp;   // May be 32-bit on legacy platforms

// New (64-bit safe)
int64_t timestamp;  // Definitely 64-bit

Most current operating systems, languages, and databases already use 64-bit time. The remaining risk lives in old hardware, on-disk formats, and network protocols that pinned the field at 32 bits—so audit long-lived systems well before 2038.

Timestamps in Different Contexts

JavaScript

Date.now()                    // 1705312800000 (milliseconds)
Math.floor(Date.now() / 1000) // 1705312800 (seconds)
new Date('2024-01-15T10:00:00Z').getTime() / 1000  // parse ISO -> seconds
new Date(timestamp * 1000)    // seconds -> Date

Python

import time
from datetime import datetime, timezone

time.time()                   # 1705312800.123456 (seconds, float)
int(time.time())              # 1705312800 (whole seconds)
datetime(2024, 1, 15, 10, tzinfo=timezone.utc).timestamp()  # date -> ts
datetime.fromtimestamp(1705312800, tz=timezone.utc)         # ts -> date

SQL

-- MySQL
SELECT UNIX_TIMESTAMP();                        -- Current
SELECT UNIX_TIMESTAMP('2024-01-15 10:00:00');   -- Specific date
SELECT FROM_UNIXTIME(1705312800);               -- To datetime

-- PostgreSQL
SELECT EXTRACT(EPOCH FROM NOW());               -- Current
SELECT TO_TIMESTAMP(1705312800);                -- To timestamptz

Frequently Asked Questions

What is a Unix timestamp?

A Unix timestamp is the number of seconds that have elapsed since the Unix Epoch—January 1, 1970, at 00:00:00 UTC. It's a single integer that identifies an exact instant in time, the same on every computer, with no timezone or formatting attached.

Is a Unix timestamp in seconds or milliseconds?

By definition, Unix time is measured in seconds. However, JavaScript (Date.now()) and many web APIs use milliseconds. Count the digits to tell them apart: a current-era value with 10 digits is seconds, 13 digits is milliseconds. Divide milliseconds by 1000 to get seconds, or multiply seconds by 1000 to get milliseconds.

What does the Z at the end of a timestamp mean?

In an ISO 8601 string like 2024-01-15T10:00:00Z, the Z means "Zulu time," which is UTC / zero offset (+00:00). It tells you the time is expressed in UTC with no timezone adjustment. A timestamp with no Z and no offset is ambiguous and should be avoided.

What is the difference between Unix time and ISO 8601?

Both describe the same instant. Unix time is a bare integer count of seconds—compact, easy to do math with, and ideal for storage and APIs. ISO 8601 (like 2024-01-15T10:00:00Z) is a human-readable string that shows the date, time, and timezone explicitly—ideal for logs, display, and debugging. They convert to each other trivially.

What is the year 2038 problem?

The Year 2038 problem (Y2K38) is an overflow bug in systems that store Unix time as a signed 32-bit integer. The maximum such value, 2147483647, is reached at 03:14:07 UTC on January 19, 2038. One second later the counter wraps to a negative number and is misread as 1901. The fix is to store time as a 64-bit integer, which is safe for hundreds of billions of years.

Summary

Unix timestamps are simple yet powerful:

  • What: seconds since January 1, 1970 UTC
  • Format: a plain integer—10 digits for seconds, 13 for milliseconds
  • The Z: means Zulu/UTC, a zero offset in ISO 8601
  • Why: language-agnostic, easy math, sortable, compact
  • Watch out for: seconds vs milliseconds, and the 32-bit Y2K38 overflow
  • Best practice: store as UTC timestamps, format to local time on display

They're the universal language of time in computing—learn them once, use them everywhere.

Need to convert timestamps? Try our Unix Timestamp Converter!

Related Topics
unix timestamp unix time unix timestamp format epoch time seconds vs milliseconds iso 8601 year 2038 datetime timezone y2k38 javascript python
Share this article

Continue Reading

Time
Notable Unix Timestamps: Epoch, Y2K38, 1672531200 and Other Milestones

A friendly reference to memorable Unix timestamps—0, 1000000000, 1234567890, 1672531200, 2147483647—and why they keep showing up in code and tests.

Time
Timezone Conversions for Global Teams

Working across timezones: understanding UTC, handling daylight saving, and tools for scheduling international meetings.

Security
JWT Tokens Decoded: Structure, Security, and Best Practices

Understanding JSON Web Tokens: the three parts of a JWT, how verification works, and security considerations for token-based authentication.