Vortenza - Free Online Tools and CalculatorsBrowse tools
Published: June 2, 2026 · Updated: June 3, 202616 min readDeveloper ToolsReviewed by Vortenza Editorial Team

Unix Timestamp Explained: Convert, Read & Use Timestamps (2026)

Abstract dark navy background showing a Unix timestamp integer converting to a human-readable date string, with a globe icon showing timezone-independence and emerald green arrows connecting clock and calendar icons

Most timestamp bugs are timezone bugs.

That is the pattern across virtually every timestamp-related production incident. The timestamp itself is fine. The conversion is fine. Someone just assumed the wrong timezone at some point in the pipeline -- the database stores in local time, the API returns UTC, the frontend displays local, and somewhere in that chain the date appears wrong by 5, 7, or 11 hours depending on where the user is sitting.

Unix timestamps exist precisely to solve this problem. A Unix timestamp is a single integer -- seconds elapsed since midnight January 1, 1970 UTC. It has no timezone. It means the same thing in every country on every server. Human-readable dates are for people. Timestamps are for systems.

This guide covers what Unix timestamps are, how to read and convert them, why the seconds-vs-milliseconds confusion causes so many bugs, and how to avoid the common mistakes that make timestamp problems hard to debug.

Key Takeaways

  • A Unix timestamp is the number of seconds elapsed since January 1, 1970 00:00:00 UTC (the Unix epoch)
  • Unix timestamps have no timezone -- they always represent UTC, and conversion to local time is a display concern
  • Store time in UTC. Convert for display.
  • The difference between seconds and milliseconds is one of the most common developer mistakes -- JavaScript's Date.now() returns milliseconds (13 digits), while most Unix systems use seconds (10 digits)
  • Most timestamp bugs are timezone bugs -- somewhere in the pipeline, UTC is mixed with local time
  • ISO 8601 format (2026-06-15T09:30:00Z) is more human-readable but Unix timestamps are faster to compare and sort
  • JWT tokens use Unix timestamp integers for exp (expiration), iat (issued at), and nbf (not before) claims
  • Always store timestamps in UTC in databases; convert to the user's local timezone only at the display layer

Quick Answer

A Unix timestamp is an integer representing the number of seconds elapsed since January 1, 1970 at 00:00:00 UTC. It is timezone-independent and is used universally in computing to represent a specific moment in time.

Timestamp Decision Framework

Use Unix Timestamps When

  • Storing machine-readable dates
  • Comparing or sorting times
  • JWT claims (exp, iat, nbf)
  • API internals between services

Use ISO 8601 When

  • Humans read the value
  • API debugging or logging
  • Documentation or config files
  • Browser or third-party clients

Rule: Store timestamps. Display dates.

Abstract dark navy background showing a Unix timestamp integer on the left converting to a human-readable date string on the right, with a globe icon beneath showing timezone-independence

Unix timestamp quick answer

The table below defines the core terminology used throughout this guide.

TermMeaning
Unix TimestampInteger count of seconds since Unix epoch (Jan 1, 1970 UTC)
Epoch (Unix Epoch)The reference starting point: January 1, 1970 00:00:00 UTC
UTCCoordinated Universal Time -- the global time standard; timestamps are always UTC
SecondsStandard Unix timestamp unit (10 digits currently: e.g., 1750000000)
Milliseconds1/1000th of a second; JavaScript's Date.now() returns milliseconds (13 digits)
ISO 8601Human-readable date standard: 2026-06-15T09:30:00Z (the Z means UTC)
Epoch millisecondsMilliseconds since Jan 1 1970 UTC; 1000x larger than Unix timestamp in seconds

Unix timestamp quick reference

Unix timestamp milestones: key timestamps and their corresponding human-readable UTC dates
TimestampHuman Date (UTC)Context
0January 1, 1970 00:00:00 UTCUnix epoch origin
1000000000September 9, 2001 01:46:40 UTCThe "one billion" moment
1700000000November 14, 2023 22:13:20 UTCRecent past
1750000000June 14, 2025 22:13:20 UTCApproximate guide publication window
1800000000January 15, 2027 01:20:00 UTCNear future reference
2147483647January 19, 2038 03:14:07 UTCYear 2038 problem boundary (32-bit max)
4102444800January 1, 2100 00:00:00 UTCFar future reference

The current timestamp when reading this guide is somewhere around 1,750,000,000. To get the exact current timestamp: Math.floor(Date.now() / 1000) in JavaScript, int(time.time()) in Python, date +%s in a Unix terminal.

What is a Unix timestamp?

Direct answer: A Unix timestamp is a single integer representing the number of seconds that have passed since midnight January 1, 1970 UTC. It is a globally consistent way to represent any point in time without timezone ambiguity.

The integer representation is the key advantage. When you store the integer 1700000000, it means exactly one thing: 1.7 billion seconds after the Unix epoch. A developer in New York and a developer in Tokyo looking at 1700000000 are looking at the same moment in time. Neither has to know the other's timezone. Neither has to worry about daylight saving time. The timestamp just says “this many seconds after a known starting point.”

A Unix timestamp is only useful when everyone agrees on the clock -- and for Unix timestamps, everyone does. The clock is UTC, the unit is seconds, and the starting point is January 1, 1970 midnight. These conventions are supported by every operating system, every programming language, every database engine, and every API.

What Unix timestamps do not carry: date, month, year, hour, minute, second, or timezone. All of that is derived by converting the integer. The integer itself is just a count.

What is Unix epoch?

Direct answer: The Unix epoch is the starting point from which Unix timestamps are counted: January 1, 1970 at exactly 00:00:00 Coordinated Universal Time (UTC). Every Unix timestamp is the number of seconds before or after this moment.

Why 1970?

Unix was developed in the late 1960s at Bell Labs. When the developers needed a consistent time reference, they chose January 1, 1970 -- a recent, round date that preceded the systems being developed. The choice was practical rather than principled; the important part was the consistency, not the specific date. There is nothing special about 1970 astronomically, historically, or computationally. It is simply the agreed-upon starting point. If Unix had been developed 10 years earlier, the epoch might be 1960. The convention stuck.

Negative timestamps

Timestamps before January 1, 1970 are represented as negative integers. January 1, 1969 is approximately -31,536,000 (roughly -365 days × 86,400 seconds per day). Most systems support negative timestamps for historical dates, though some applications and older systems handle only positive values.

UTC standardization

The epoch is defined in UTC, not in any local timezone. This is what makes the system timezone-independent. “January 1, 1970 midnight” means midnight in UTC specifically -- not midnight in New York or London or Tokyo.

How Unix timestamps work

Direct answer: A Unix timestamp counts seconds continuously upward from the epoch. Every second that passes increases the timestamp by 1. The count never resets and is independent of timezones, daylight saving, calendars, or geographic location.

The arithmetic

  • One day = 86,400 seconds (24 × 60 × 60)
  • One week = 604,800 seconds
  • One month (30 days) ≈ 2,592,000 seconds
  • One year (365 days) ≈ 31,536,000 seconds

Converting to human time (JavaScript, Python, Terminal):

// JavaScript
new Date(1700000000 * 1000)           // multiply by 1000 for ms
new Date(1700000000 * 1000).toISOString()  // "2023-11-14T22:13:20.000Z"

# Python
from datetime import datetime, timezone
datetime.fromtimestamp(1700000000, tz=timezone.utc)
# datetime(2023, 11, 14, 22, 13, 20, tzinfo=timezone.utc)

# Terminal
date -d @1700000000        # Linux
date -r 1700000000         # macOS

The one-way relationship

A Unix timestamp maps to exactly one UTC moment. One UTC moment maps to exactly one Unix timestamp. The conversion is bijective (one-to-one in both directions) for UTC times from the epoch forward.

Abstract number line on dark navy background with the epoch marked at left in medium teal, the current timestamp region glowing in bright emerald, and future and past timestamps fading toward each end

Unix timestamp vs human dates

AspectUnix TimestampHuman Date String
FormatSingle integer: 1700000000Text: November 14, 2023 10:13 PM
TimezoneNone (always UTC)Embedded or implied
ComparisonSimple integer comparisonRequires parsing
SortingNumerically sortableRequires format consistency
Storage4-8 bytes10-30+ bytes as string
Human readabilityNone without conversionYes
DST ambiguityNoneYes (local time during transition hours)
Language supportUniversal (standard library)Varies by locale and format
Database indexingEfficient (integer index)Less efficient (string index)

Human-readable dates are for people. Timestamps are for systems. The right architecture stores timestamps as integers (or UTC datetime fields) in the database and converts to human-readable format only when displaying to users.

Unix timestamp: seconds vs milliseconds

Direct answer: Unix timestamps are traditionally in seconds (10 digits, e.g., 1700000000). JavaScript's Date.now() returns milliseconds (13 digits, e.g., 1700000000000). Confusing the two is one of the most common timestamp bugs.

UnitDigitsExampleSource
Seconds101700000000Unix system time, Python int(time.time()), most APIs
Milliseconds131700000000000JavaScript Date.now(), Java System.currentTimeMillis()
Microseconds161700000000000000Python time.time_ns() / 1000, some high-precision systems
Nanoseconds191700000000000000000Python time.time_ns(), Linux clock_gettime

The most common mistake

Passing a millisecond timestamp where a second timestamp is expected. If your JWT library expects exp in seconds and you pass Date.now() (milliseconds), the token appears to expire 1000 years in the future. If your API accepts seconds and you pass milliseconds, dates appear in the year 55,739.

How to identify and convert between units:

// Check which unit your timestamp is in
const ts = 1700000000;
const isSeconds = ts.toString().length === 10;
const isMilliseconds = ts.toString().length === 13;

// Convert between units
const fromSeconds = ts * 1000;         // seconds to milliseconds
const fromMilliseconds = ts / 1000;    // milliseconds to seconds

// Get current timestamp
Date.now()                             // milliseconds (13 digits)
Math.floor(Date.now() / 1000)          // seconds (10 digits)
import time
time.time()               # float: 1700000000.123 (seconds)
int(time.time())          # int: 1700000000 (seconds)
int(time.time() * 1000)   # milliseconds

Database columns

PostgreSQL TIMESTAMP stores microseconds internally. MySQL DATETIME stores to seconds by default, DATETIME(3) for milliseconds. MongoDB stores dates as milliseconds since epoch internally. Being explicit about what unit your application code uses avoids conversion bugs at the database layer.

Real example 1: convert timestamp to date

Input: 1700000000

1

Identify the unit

10 digits → seconds.

2

Convert using any language

// JavaScript
new Date(1700000000 * 1000).toISOString()
// "2023-11-14T22:13:20.000Z"  (November 14, 2023, 10:13:20 PM UTC)

# Python
from datetime import datetime, timezone
datetime.fromtimestamp(1700000000, tz=timezone.utc).isoformat()
# "2023-11-14T22:13:20+00:00"

# Terminal (Linux)
date -d @1700000000 --utc
# Tue Nov 14 22:13:20 UTC 2023
3

Interpret the result

1700000000 = November 14, 2023 at 22:13:20 UTC. If displaying to a user in New York (UTC-5 in November), the local display would be November 14, 2023 at 5:13:20 PM EST. The timestamp itself is unchanged; only the display representation changes.

Reverse conversion (date to timestamp):

// JavaScript
Math.floor(new Date('2023-11-14T22:13:20Z').getTime() / 1000)
// 1700000000

# Python
int(datetime(2023, 11, 14, 22, 13, 20, tzinfo=timezone.utc).timestamp())
# 1700000000

The Z at the end of the ISO date string is critical -- it specifies UTC. Without it, the conversion uses the local timezone and produces a different timestamp.

Real example 2: JWT token expiration

Direct answer: JWT tokens use Unix timestamps (in seconds) for three time-related claims: exp (when the token expires), iat (when it was issued), and nbf (when it first becomes valid).

A decoded JWT payload:

{
  "sub": "user_123",
  "iss": "auth.myapp.com",
  "iat": 1749996400,
  "exp": 1750000000,
  "nbf": 1749996400
}

iat: 1749996400 → June 14, 2025 at approximately 21:00 UTC (issued at)

exp: 1750000000 → June 14, 2025 at approximately 22:13 UTC (expires approximately 73 minutes after issue)

nbf: 1749996400 → Same as iat -- the token is valid immediately from issue time

The expiration check:

const payload = decodeJWT(token);
const now = Math.floor(Date.now() / 1000);  // current time in seconds
const isExpired = payload.exp < now;

Most common JWT timestamp mistake

Using Date.now() directly instead of Math.floor(Date.now() / 1000). Date.now() returns milliseconds. payload.exp is in seconds. Comparing 1750000000 (exp in seconds) against 1750000000000 (Date.now() in milliseconds) incorrectly concludes the token has been expired for 999 years.

Second most common mistake

Not accounting for clock skew. If the issuing server and the verifying server have clocks that differ by more than a few seconds, tokens may appear expired before they actually are. JWT libraries typically allow a configurable clock skew tolerance (often 30-60 seconds).

The full JWT guide is at JWT Tokens Explained.

Real example 3: API response timestamps

Direct answer: APIs return timestamps in various formats. Understanding which format to expect (and how to parse each) prevents display bugs.

A typical API response with timestamps:

{
  "id": "order_abc123",
  "status": "completed",
  "created_at": 1700000000,
  "updated_at": "2023-11-14T22:13:20Z",
  "processed_at": "2023-11-14T22:13:20.456+00:00",
  "expires_at": null
}
FieldFormatParse approach
created_at: 1700000000Unix seconds (integer)new Date(1700000000 * 1000)
updated_at: "2023-11-14T22:13:20Z"ISO 8601 UTCnew Date("2023-11-14T22:13:20Z")
processed_at: "...T22:13:20.456+00:00"ISO 8601 with ms and offsetnew Date("2023-11-14T22:13:20.456+00:00")
expires_at: nullNull (no expiration)Check for null before parsing

What to document in API specs

  • Is the timestamp in seconds or milliseconds?
  • Is the string format ISO 8601? If so, is timezone always explicit?
  • Are all timestamps in UTC, or can they vary by user timezone?
  • Are null values possible, and what do they mean?
Abstract API JSON response card on dark navy background showing three timestamp fields -- an integer in emerald green, an ISO string in medium teal, and a null value in muted gray

UTC vs local time

Direct answer: UTC (Coordinated Universal Time) is the global time standard that Unix timestamps use. Local time is UTC adjusted by a timezone offset. Store UTC. Convert for display.

AspectUTCLocal Time
DefinitionThe global reference clockUTC adjusted by timezone offset (+/- hours)
Daylight Saving TimeNever observes DSTMay shift by 1 hour in regions with DST
AmbiguityNoneYes -- 2:30 AM during fall DST clock change
Database storageRecommendedDiscouraged
API transmissionStandardError-prone
Sorting and comparisonSafe and consistentRequires normalization
Example2023-11-14T22:13:20Z2023-11-14T17:13:20-05:00 (EST)

The DST problem

Daylight Saving Time creates a genuine ambiguity. In the US, clocks “fall back” on the first Sunday in November. At 2:00 AM, clocks return to 1:00 AM. This means 1:30 AM occurs twice in one night. If a database stores local time (1:30 AM EST), there is no way to determine which occurrence it refers to. UTC has no DST -- 22:30:00 UTC on November 5, 2023 is unambiguous.

A timestamp is only useful when everyone agrees on the clock -- and UTC is the clock everyone agrees on.

Abstract diagram on dark navy background showing UTC as a single reference point with multiple local timezone offset branches representing different regions of the world

Common timestamp mistakes

Timezone assumptions break more software than timestamp calculations.

1

Seconds vs milliseconds mismatch

Symptom: Passing Date.now() (13-digit milliseconds) where seconds are expected, or vice versa

Fix: Dates appear thousands of years in the future, or everything shows January 1, 1970. Count digits to identify which you have; explicitly convert before using.

2

Storing local time instead of UTC

Symptom: Storing 2023-11-14 17:13:20 (local EST) instead of 2023-11-14T22:13:20Z (UTC)

Fix: Dates shift by the server's timezone offset when the server moves or when users are in different timezones. Always store UTC; store timezone separately if you need to reconstruct original local time.

3

Assuming server timezone

Symptom: Code calls new Date() or datetime.now() without specifying UTC

Fix: Queries return different results in different server environments (local vs staging vs production). Always use UTC-explicit functions: new Date().toISOString(), datetime.now(timezone.utc).

4

DST boundary errors

Symptom: Logic that adds exactly 24 hours crosses DST boundaries incorrectly

Fix: A 'same time tomorrow' calculation arrives 1 hour early or late on DST change days. Use date arithmetic (add 1 day) rather than duration arithmetic (add 86,400 seconds) when crossing DST boundaries.

5

Not validating timestamp format from external sources

Symptom: Accepting any integer as a Unix timestamp without checking seconds vs milliseconds

Fix: Document expected format in API contracts; validate range (10 digits = seconds, 13 digits = milliseconds).

Why timestamp bugs happen

Direct answer: Most timestamp bugs arise from one of four sources: unit mismatch (seconds vs milliseconds), timezone assumptions (UTC vs local), DST transitions, or inconsistency between where timestamps are generated and where they are consumed.

Bug PatternRoot CauseSymptomFix
Date off by hoursUTC vs local time mixEvents appear at wrong timeStore UTC, convert at display only
Date off by 1000 yearsMilliseconds where seconds expectedexp of JWT is year 55,739Divide by 1000 before using
Date stuck at 1970Seconds where milliseconds expectedEverything shows January 1, 1970Multiply by 1000 before using
Date ambiguous in fallDST fall-backTwo events at 'same time'Use UTC storage, avoid local time
Different results dev vs prodServer timezone variesWorks locally, wrong in productionUse UTC functions explicitly
Expiry check incorrectClock skew between servicesTokens appear expired earlyAdd clock skew tolerance (30-60 sec)
Sorting incorrectMixed timestamp formatsRecords in wrong orderNormalize all timestamps to one format
Null timestamp throws errorNot checking for null before parsingRuntime exceptionCheck for null before new Date()

When a date is wrong, first check whether it is off by a round number of hours (timezone issue), off by exactly 1000x (unit issue), or ambiguous around a DST boundary. These three checks resolve most timestamp bugs.

Unix timestamp converter example

Converting a timestamp manually requires knowing the calendar arithmetic for handling leap years, month lengths, and so on. In practice, nobody does this by hand -- but knowing the conversion exists in every language is useful.

For debugging -- checking what exp: 1750000000 in a JWT actually means, verifying a date stored in a database, or confirming that a cron schedule will fire at the right UTC time -- a timestamp converter is the right tool. Many developers validate date calculations using the Vortenza Unix Timestamp Converter before deploying production systems. Paste a timestamp, see the UTC date and time, convert to any timezone, and verify the calculation.

The typical debugging workflow

  1. Find the timestamp value in the JWT payload, database record, or API response
  2. Paste it into the converter to read the human date
  3. Verify it matches the expected date and time
  4. If wrong, check whether seconds vs milliseconds conversion is the issue
  5. Verify the timezone of the expected result against UTC

Unix timestamp vs ISO 8601

AspectUnix TimestampISO 8601
FormatInteger: 1700000000String: 2023-11-14T22:13:20Z
Human readabilityNone without conversionReadable directly
Comparison/sortingSimple integer comparisonString comparison works if consistent
Storage space4-8 bytes (integer)20-30 bytes (string)
Timezone clarityImplicitly UTCExplicit with Z or offset
Millisecond precisionYes (13-digit variant)Yes (2023-11-14T22:13:20.456Z)
Language supportUniversalNearly universal
JSON serializationNumber typeString type
Database storageEfficient integer columnString or datetime column
API compatibilityDepends on clientGenerally preferred for REST APIs

When to use each

Unix timestamps for: internal database storage, JWT claims, performance-critical comparisons and sorting, log timestamps, inter-service communication where both sides are code.

ISO 8601 for: REST API responses consumed by browsers or third-party clients, human-readable logs, configuration files, any context where a developer might read the value directly. Many modern APIs return both: the integer for programmatic use and the ISO string for human debugging.

Database timestamp best practices

Direct answer: Store timestamps in UTC. Use native datetime types rather than integer columns when possible. Convert to the user's local timezone only at the display layer.

PostgreSQL:

-- Use TIMESTAMPTZ (timestamp with time zone) -- stores in UTC internally
CREATE TABLE events (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255),
    created_at TIMESTAMPTZ DEFAULT NOW(),
    scheduled_at TIMESTAMPTZ NOT NULL
);

-- Insert with explicit UTC
INSERT INTO events (name, scheduled_at)
VALUES ('Meeting', '2023-11-14 22:13:20+00');

-- Query and convert to display timezone at query time
SELECT name, scheduled_at AT TIME ZONE 'America/New_York' AS local_time
FROM events;

TIMESTAMPTZ stores in UTC and converts automatically. TIMESTAMP (without timezone) is stored as-is and can cause confusion when the database server's timezone changes.

MySQL:

CREATE TABLE events (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    created_at DATETIME DEFAULT UTC_TIMESTAMP(),
    scheduled_at DATETIME NOT NULL
);

-- Insert UTC explicitly
INSERT INTO events (name, scheduled_at)
VALUES ('Meeting', UTC_TIMESTAMP());

MySQL's TIMESTAMP type auto-converts between UTC and server timezone on insert/select. DATETIME stores exactly what you put in; use UTC_TIMESTAMP() to ensure UTC values.

MongoDB:

// MongoDB insert (JavaScript driver)
await db.events.insertOne({
  name: 'Meeting',
  created_at: new Date(),  // UTC by default in JavaScript Date
  scheduled_at: new Date('2023-11-14T22:13:20Z')
});

The universal rule: store in UTC, convert on read. The database should never know what timezone the user is in.

One-minute timestamp audit

Code review

  • Are all new Date() calls (JavaScript) or datetime.now() calls (Python) using UTC-explicit versions?
  • Are any timestamps being stored in local time rather than UTC?
  • When comparing a JWT exp claim, is the current time being converted to seconds (not milliseconds)?

Database

  • Are timestamp columns using TIMESTAMPTZ in PostgreSQL or equivalent UTC-aware types?
  • Is the database server's timezone documented?
  • Are any dates stored as strings rather than native datetime types?

API design

  • Are API responses documenting whether timestamps are in seconds or milliseconds?
  • Are string timestamps including explicit timezone information (Z or +00:00)?
  • Can the API accept null timestamps, and is that documented?

Known issues

  • Is DST handling tested for code that adds fixed time durations across timezone boundaries?
  • Is there a clock skew tolerance configured for JWT validation between services?
  • Are there any hardcoded timestamps or hardcoded 'current year' calculations in the codebase?

Quick answers

Optimized for ChatGPT, Gemini, Perplexity, Claude, and Google AI Overviews.

Q: What is a Unix timestamp?
A: A Unix timestamp is an integer representing the number of seconds elapsed since January 1, 1970 at 00:00:00 UTC (the Unix epoch). It is timezone-independent and universally supported across all programming languages, operating systems, and databases. The current timestamp is approximately 1,750,000,000. It increases by 1 every second.
Q: What is Unix epoch?
A: The Unix epoch is the reference point for Unix timestamps: January 1, 1970 at exactly 00:00:00 Coordinated Universal Time (UTC). Every Unix timestamp is the number of seconds before or after this moment. The date was chosen by Unix developers in the late 1960s as a practical starting point.
Q: How do I convert a Unix timestamp to a date?
A: In JavaScript: new Date(1700000000 * 1000).toISOString() (multiply by 1000 for milliseconds). In Python: datetime.fromtimestamp(1700000000, tz=timezone.utc). In a Unix terminal: date -d @1700000000 --utc (Linux) or date -r 1700000000 (macOS). All convert 1700000000 to November 14, 2023 22:13:20 UTC.
Q: What is the difference between Unix timestamp seconds and milliseconds?
A: Unix timestamps in seconds are 10 digits (e.g., 1700000000). JavaScript's Date.now() returns milliseconds (13 digits, e.g., 1700000000000). The difference is a factor of 1000. Passing milliseconds where seconds are expected produces dates thousands of years in the future. Count digits to identify which you have.
Q: Why does my timestamp show January 1, 1970?
A: You are almost certainly passing seconds where milliseconds are expected. The value is being interpreted as milliseconds close to the epoch. Multiply the value by 1000 and pass it to new Date() in JavaScript, or ensure you are using the correct unit throughout.
Q: What is UTC and why do timestamps use it?
A: UTC (Coordinated Universal Time) is the global time standard from which all other timezones are defined. Unix timestamps use UTC because it has no daylight saving time, no political adjustments, and a stable relationship with international atomic time. A timestamp in UTC means the same thing everywhere in the world.
Q: What is the Year 2038 problem?
A: The Year 2038 problem is a potential overflow issue for systems storing Unix timestamps as 32-bit signed integers. The maximum 32-bit signed integer (2,147,483,647) corresponds to January 19, 2038 at 03:14:07 UTC. After that second, a 32-bit counter overflows to a large negative number. Systems using 64-bit integers are not affected.
Q: How do I get the current Unix timestamp?
A: In JavaScript: Math.floor(Date.now() / 1000) (seconds) or Date.now() (milliseconds). In Python: int(time.time()) (seconds). In PHP: time() (seconds). In Go: time.Now().Unix() (seconds). In a Unix terminal: date +%s. All return the current number of seconds since January 1, 1970 UTC.
Q: What are JWT timestamp claims?
A: JWT tokens use three Unix timestamp claims (in seconds): exp (expiration -- the token is invalid after this time), iat (issued at -- when the token was created), and nbf (not before -- the token is invalid before this time). Always compare them against Math.floor(Date.now() / 1000) in JavaScript, not against Date.now().
Q: What is ISO 8601 and how does it relate to Unix timestamps?
A: ISO 8601 is a human-readable date format: 2023-11-14T22:13:20Z. The Z suffix indicates UTC. Both ISO 8601 and Unix timestamps represent moments in time formatted differently. Unix timestamps are better for storage and comparison; ISO 8601 strings are better for APIs and human debugging. The same moment: 1700000000 and 2023-11-14T22:13:20Z.
Q: How do I store timestamps in a database?
A: Use the database's native datetime type with timezone support: TIMESTAMPTZ in PostgreSQL, DATETIME with explicit UTC insertion in MySQL, or MongoDB's native Date type. Store all timestamps in UTC. Never store in local time. Convert to the user's timezone only at the display layer in the application.
Q: Why does my timestamp look wrong in a different timezone?
A: The timestamp is correct (it always represents a UTC moment), but the display conversion is using the wrong timezone. Check: is the conversion using the user's timezone or the server's timezone? Are you using UTC-explicit functions, or functions that default to local time? Is DST being handled correctly for the target timezone?
Q: Can Unix timestamps represent dates before 1970?
A: Yes, as negative integers. January 1, 1960 is approximately -315,619,200. Most modern systems and languages support negative Unix timestamps for historical dates. However, some older systems and certain libraries handle only non-negative timestamps.
Q: What timezone does a Unix timestamp represent?
A: A Unix timestamp is always UTC. It has no timezone of its own -- it is simply a count of seconds since the UTC epoch. When you convert a Unix timestamp to a human date, you choose a timezone for display. The timestamp itself does not change; only the display format reflects the timezone.
Q: How do I add or subtract time from a Unix timestamp?
A: Add or subtract seconds directly. One hour from now: currentTimestamp + 3600. One day from now: currentTimestamp + 86400. One week: currentTimestamp + 604800. For adding calendar months or years (which have variable lengths), use a date library rather than fixed-second arithmetic to handle month length and leap year differences correctly.

For full explanations, see the Frequently asked questions section below or the FAQ accordion.

Frequently asked questions

Full explanations with context. For concise answers, see Quick answers above.

What is a Unix timestamp and why is it used everywhere?

+

A Unix timestamp is an integer representing seconds elapsed since January 1, 1970 UTC. It is used everywhere in computing because it solves the fundamental problem of representing time across different systems, languages, operating systems, and geographic locations. An integer like 1700000000 means exactly the same thing on every server in every country. Human-readable dates like 'November 14, 2023 5:13 PM EST' require knowing the timezone to interpret correctly and cannot be directly compared or sorted without parsing. Unix timestamps avoid all of that.

Why does Unix time start in 1970?

+

Unix was developed in the late 1960s at Bell Labs. When developers needed a consistent reference point for system time, they chose January 1, 1970 -- a recent, round date that predated the systems being developed. The choice was practical rather than principled. There is nothing computationally, astronomically, or historically special about 1970. It was just a convenient starting point close enough to the development era to use reasonably-sized numbers. The convention was adopted widely and is now standardized in POSIX.

What is UTC and why should I store timestamps in it?

+

UTC (Coordinated Universal Time) is the global time standard. Every timezone is defined as UTC plus or minus an offset. UTC never observes daylight saving time and never changes. Storing timestamps in UTC means: the value means the same thing regardless of which server processes it, there is no ambiguity during DST transitions, moving a server to a different timezone does not corrupt stored dates, and comparing timestamps from different sources works without normalization. The only time local timezone information belongs in a database is when you specifically need to record 'what time it was in the user's local timezone' -- a different data point from the UTC moment.

How do I convert a Unix timestamp to a date in my programming language?

+

JavaScript (browser): new Date(timestamp * 1000).toISOString() -- multiply by 1000 to convert seconds to milliseconds. Node.js: same as browser, or new Date(timestamp * 1000).toUTCString(). Python: datetime.fromtimestamp(timestamp, tz=timezone.utc) from the datetime module. PHP: date('Y-m-d H:i:s', timestamp). Go: time.Unix(timestamp, 0).UTC(). Java: Instant.ofEpochSecond(timestamp). Ruby: Time.at(timestamp).utc. SQL: PostgreSQL's to_timestamp(timestamp).

Why is my timestamp wrong by exactly a few hours?

+

An error of a specific number of hours (5, 7, 11, etc.) is almost always a timezone problem. The most common cause: the timestamp was generated or stored in local time instead of UTC, or the display conversion is using the server's timezone instead of the user's timezone. Check whether your timestamp generation uses UTC-explicit functions. Check whether your database's datetime column is TIMESTAMPTZ (UTC-aware) or TIMESTAMP (timezone-naive). Check whether your display conversion specifies the intended timezone or defaults to local.

What is the Year 2038 problem?

+

The Year 2038 problem is a timestamp overflow issue for systems that store Unix timestamps in 32-bit signed integers. The maximum 32-bit signed integer (2,147,483,647) corresponds to January 19, 2038 at 03:14:07 UTC. After this moment, a 32-bit signed counter overflows and wraps to a large negative number, potentially causing systems to display dates in 1901 or crash. Modern systems using 64-bit integers for timestamps (which can store dates billions of years into the future) are not affected. The issue primarily concerns legacy embedded systems and older code.

How do JWT tokens use Unix timestamps?

+

JWT tokens include three Unix timestamp claims in the payload: exp (expiration -- the timestamp after which the token is invalid), iat (issued at -- when the token was created), and nbf (not before -- the timestamp before which the token is invalid). All three are in seconds, not milliseconds. To check expiration: compare payload.exp against Math.floor(Date.now() / 1000) in JavaScript. Never compare against Date.now() directly -- the milliseconds vs seconds mismatch causes incorrect results. JWT libraries typically handle this automatically when you use their verify() function.

When should I use Unix timestamps vs ISO 8601 strings?

+

Use Unix timestamps for: database storage (efficient integer columns), JWT claims, inter-service API communication where both ends are code, performance-critical sorting and comparison, and log timestamps in high-volume systems. Use ISO 8601 strings for: REST API responses consumed by browsers or third-party clients, human-readable logs, configuration files, any context where a developer or operator might read the value directly. When in doubt, provide both: 'created_at': 1700000000, 'created_at_iso': '2023-11-14T22:13:20Z'.

What is the difference between TIMESTAMP and TIMESTAMPTZ in PostgreSQL?

+

TIMESTAMP (without timezone) stores a datetime value exactly as given, with no timezone conversion. TIMESTAMPTZ (timestamp with time zone) stores the value in UTC internally and converts to the session timezone on display. For most applications, TIMESTAMPTZ is the correct choice because it ensures consistent UTC storage regardless of the database server's timezone setting. TIMESTAMP can cause incorrect behavior if the server's timezone changes or if you insert values in different timezones. PostgreSQL's documentation recommends TIMESTAMPTZ for most use cases.

How do I handle daylight saving time with timestamps?

+

Unix timestamps do not observe DST -- they are always UTC. If you store timestamps as Unix integers or in TIMESTAMPTZ columns, DST is not your concern at the storage layer. DST only becomes an issue when you convert to local time for display: the UTC time 2023-11-05 06:30:00Z converts to 2023-11-05 01:30:00 EST (eastern standard time after fall-back), while 2023-11-05 05:30:00Z (one hour earlier) also converts to 2023-11-05 01:30:00 EDT (eastern daylight time before fall-back). These are two different UTC moments that display as the same local time. A timezone-aware library handles this correctly; manual offset arithmetic does not.

Can I use timestamps to sort events from different timezones?

+

Yes, and this is one of the main advantages of Unix timestamps. Because all timestamps represent UTC moments, sorting by timestamp sorts events in the correct global chronological order regardless of where each event originated. If user A in New York created a record at 9:00 AM EST and user B in London created a record at 3:00 PM GMT (both UTC+0), the London record has a later UTC timestamp and correctly sorts after the New York record. This breaks immediately if timestamps are stored in local time rather than UTC.

What happens to Unix timestamps on leap seconds?

+

Unix timestamps technically do not account for leap seconds -- they assume every day has exactly 86,400 seconds. When a leap second is inserted (which has happened about 27 times since 1972), the Unix timestamp 'smears' the leap second or repeats a second. In practice, most systems use UTC-SLS (Coordinated Universal Time with Smoothed Leap Second) or Google's leap second smearing, which distributes the extra second across a time window. For most applications, this is irrelevant. For extremely high-precision timing systems, leap second handling needs explicit consideration.

What is the maximum Unix timestamp?

+

For 64-bit systems (which includes virtually all modern systems), the maximum Unix timestamp is 9,223,372,036,854,775,807 -- a date approximately 292 billion years in the future, far beyond any practical concern. For legacy 32-bit systems, the maximum is 2,147,483,647, representing January 19, 2038 (the Year 2038 problem). Most modern systems and programming languages use 64-bit integers for timestamps by default. JavaScript uses 64-bit floating point, which gives safe integer precision up to approximately year 275,760.

Why does my API return a timestamp that looks like a date string, not a number?

+

Many APIs return timestamps as ISO 8601 strings ('2023-11-14T22:13:20Z') rather than Unix integers because strings are more immediately readable by developers and work consistently across JSON parsers (which do not have a native timestamp type). Both formats represent the same moment. To convert an ISO string to a Unix timestamp: Math.floor(new Date('2023-11-14T22:13:20Z').getTime() / 1000) in JavaScript. The choice between format is an API design decision; what matters is that the timezone is explicit (the Z in the string or the fact that integers are always UTC).

How do I work with timestamps in different programming languages safely?

+

The key rules across all languages: always specify UTC explicitly when creating timestamps (do not rely on system timezone defaults), always check the unit (seconds vs milliseconds -- differs by language), and use the language's standard library rather than manual arithmetic. Dangerous: new Date() in Node.js (uses local timezone in some contexts), datetime.now() in Python (uses local time), Date::now() in Ruby (uses UTC -- safe). Safe: new Date().toISOString() (always UTC), datetime.now(timezone.utc) or datetime.utcnow() in Python, DateTime.UtcNow in C#.

Should APIs return Unix timestamps or ISO 8601 dates?

+

Both have legitimate uses and the best answer depends on your API's consumers. Unix timestamps (integers) are better for programmatic consumers: compact, unambiguous, no parsing required, and fast to compare. ISO 8601 strings are better for human-readable APIs, browser clients, and any context where developers inspect payloads directly. The best practice for public REST APIs is to return ISO 8601 strings with explicit UTC offset (the Z suffix or +00:00), and optionally include the Unix integer alongside. Never return local time strings without an explicit timezone offset -- that is the pattern that causes timezone bugs in consumers.

Final verdict

Unix timestamps are the practical foundation of time handling in software. A single integer, always UTC, always increasing, always meaning the same thing everywhere. The simplicity is the point.

Store time in UTC. Convert for display. Every time a timestamp problem appears, check those two things first.

The biggest mistakes: storing local time in databases (causes timezone-dependent results), mixing seconds and milliseconds (causes wildly wrong dates), and not validating timestamp formats from external APIs (causes runtime errors on null or unexpected types).

Many developers use the Vortenza Unix Timestamp Converter to quickly verify timestamp calculations and timezone conversions. Paste a timestamp, see the UTC date, convert to any timezone, and verify the calculation matches the expected value -- faster than opening a REPL and writing conversion code.

Tools used in this guide

About this guide

Published by the Vortenza Editorial Team. Unix epoch specification referenced from the POSIX.1-2017 standard (IEEE Std 1003.1-2017). Year 2038 problem documented by the GNU C Library Y2038 migration guide and the Linux kernel time64 transition. PostgreSQL TIMESTAMP vs TIMESTAMPTZ behavior from the PostgreSQL 16 documentation. JWT timestamp claims from RFC 7519. Leap second insertion count (27 since 1972) from IERS Bulletin C. Leap second smearing approach from Google's leap second smearing documentation.