Web Development
Unix Timestamps and Epoch Time: The Complete Developer Guide
Understand Unix, POSIX and epoch timestamps with verified examples, seconds vs milliseconds, UTC rules, Linux commands, code conversions and timestamp limits.
A Unix timestamp expresses time relative to January 1, 1970, at 00:00:00 UTC, usually as a number of seconds. It is also commonly called POSIX time or Unix epoch time. Leap seconds are excluded from this representation.
For example, 1780412400 Unix seconds means 2026-06-02T15:00:00Z. The same instant expressed in milliseconds is 1780412400000.
To inspect a value, use the Unix timestamp converter. For code and data pipelines, establish three things first: the epoch, the unit, and the supported range.
What is a Unix timestamp?
A Unix timestamp is a numeric representation of an instant relative to the Unix epoch. It does not contain a timezone name, formatting instructions, or a calendar date string. The producer and consumer must agree on its unit.
Unix timestamp, POSIX time, and epoch time: what is the difference?
| Term | Meaning |
|---|---|
| Unix epoch | The reference instant: 1970-01-01T00:00:00Z. |
| Unix time | A numeric representation of time relative to the Unix epoch. |
| Unix timestamp | A particular value in that representation, such as 1780412400 seconds. |
| POSIX time | The standardized seconds-since-the-epoch representation commonly associated with Unix time. |
| Epoch time | Often means Unix time, but “epoch” alone does not identify a particular origin or unit. |
| Epoch seconds | A count expressed in seconds; confirm which epoch the system uses. |
| UTC | The time reference used to define the Unix epoch, rather than a numeric timestamp format. |
An API field called epoch is less informative than one called unix_seconds. A number alone cannot tell you whether its producer meant seconds, milliseconds, or another convention.
What does POSIX mean by “seconds since the epoch”?
POSIX defines a relationship between UTC calendar fields and an epoch value, accounting for each calendar day as 86,400 seconds. It describes the value as an approximation of elapsed seconds rather than a continuous count of every physical second.
The primary reference is The Open Group Base Specifications, Issue 8, section 4.19, “Seconds Since the Epoch.” Older Issue 7 references use section 4.16. Read the POSIX definition.
Reference table: notable epoch values
The following are fixed reference values, not a live clock. All dates are UTC.
| Unix timestamp in seconds | UTC date and time | Meaning |
|---|---|---|
-1 | 1969-12-31T23:59:59Z | One second before the epoch, where supported |
0 | 1970-01-01T00:00:00Z | The Unix epoch |
1 | 1970-01-01T00:00:01Z | One second after the epoch |
86400 | 1970-01-02T00:00:00Z | Start of the next UTC calendar day |
1000000000 | 2001-09-09T01:46:40Z | First 10-digit positive epoch-seconds value |
1234567890 | 2009-02-13T23:31:30Z | Sequential-digit reference value |
1725151258 | 2024-09-01T00:40:58Z | A worked timestamp-to-date example |
1780412400 | 2026-06-02T15:00:00Z | The example used throughout this guide |
2147483647 | 2038-01-19T03:14:07Z | Signed 32-bit epoch-seconds maximum |
The epoch value 0 means midnight at the beginning of January 1, 1970. It does not mean “missing,” “unknown,” or “not initialized.” Use an explicit nullable field or another documented state for those meanings.
For a changing value, the timestamp converter’s current epoch display uses your device clock. An incorrect device clock produces an incorrect current timestamp.
Seconds vs milliseconds: the 1000x bug
POSIX seconds-since-the-epoch values use seconds. Other APIs can express time since the same epoch in milliseconds, microseconds, or nanoseconds.
JavaScript’s Date API uses milliseconds. That does not mean every JavaScript-facing API expects milliseconds: an API can explicitly require Unix seconds.
Here is one instant expressed in four units:
| Unit | Units per second | Example value |
|---|---|---|
| Seconds | 1 | 1780412400 |
| Milliseconds | 1000 | 1780412400000 |
| Microseconds | 1000000 | 1780412400000000 |
| Nanoseconds | 1000000000 | 1780412400000000000 |
More digits describe finer units; they do not prove that the source clock measures time that accurately.
Conversion rules
milliseconds = seconds × 1,000
microseconds = seconds × 1,000,000
nanoseconds = seconds × 1,000,000,000
seconds = milliseconds ÷ 1,000
Dividing can produce a fractional result. If the destination requires whole seconds, choose and document a rounding rule.
For example, flooring -0.5 gives -1, while truncating it toward zero gives 0. This difference matters for dates before the epoch.
Are Unix timestamps always 10 digits?
No. Around the present day, positive timestamps commonly have:
- 10 digits in seconds.
- 13 digits in milliseconds.
- 16 digits in microseconds.
- 19 digits in nanoseconds.
These are diagnostic clues, not format guarantees. Earlier dates have shorter values; later dates have longer ones. Unix seconds first reached 10 digits in 2001 and reach 11 digits on November 20, 2286.
Use the producer’s documented unit instead of guessing from length. Toolk’s converter uses a length heuristic, which is convenient for contemporary values but should not define an API contract.
Time zones: store UTC, convert at display
A Unix timestamp uses an epoch defined in UTC, but the number does not contain a timezone. A timezone determines how an instant appears on a calendar or clock.
These date strings describe the same instant:
2026-06-02T15:00:00Z
2026-06-02T21:00:00+06:00
2026-06-03T00:00:00+09:00
Each corresponds to 1780412400 Unix seconds. Changing the display timezone must not change that stored value.
UTC offset versus timezone
An offset such as +06:00 identifies a displacement from UTC for a particular date and time. A named timezone such as Asia/Dhaka or America/New_York provides calendar rules, including historical changes and daylight-saving transitions where applicable.
Those rules come from the IANA Time Zone Database.
Store instants and calendar intentions differently
For an event that already happened, an absolute instant is usually the right representation. Examples include a payment receipt, login, or log entry.
For “run every Monday at 9 AM in New York,” preserve the local schedule and named timezone. A single timestamp cannot express that recurring intention. Decide how to handle local times that do not exist or occur twice during daylight-saving transitions.
Similarly, a birthday or invoice due date may be a date-only value, not midnight UTC.
Use the time zone converter to compare displays of an instant across locations.
Converting epoch time to a human date and back
JavaScript
JavaScript Date accepts milliseconds since the Unix epoch. Multiply whole Unix seconds by 1000 before constructing a date, and use toISOString() for UTC output. These behaviors are defined in the ECMAScript Date specification.
const unixSeconds = 1780412400;
// Unix seconds → UTC date string
new Date(unixSeconds * 1000).toISOString();
// "2026-06-02T15:00:00.000Z"
// UTC date string → Unix seconds
Math.floor(Date.parse("2026-06-02T15:00:00Z") / 1000);
// 1780412400
// Current time in each unit
const currentMilliseconds = Date.now();
const currentSeconds = Math.floor(currentMilliseconds / 1000);
The same number passed with the wrong unit produces a very different date:
// Wrong unit: Date interprets this as milliseconds.
new Date(1780412400).toISOString();
// "1970-01-21T14:33:32.400Z"
// Correct: convert seconds to milliseconds.
new Date(1780412400 * 1000).toISOString();
// "2026-06-02T15:00:00.000Z"
Validate before converting
This helper deliberately accepts only whole seconds supplied as a JavaScript number:
function unixSecondsToIso(seconds) {
if (!Number.isSafeInteger(seconds)) {
throw new TypeError("Expected Unix seconds as a safe integer");
}
const milliseconds = seconds * 1000;
if (
!Number.isSafeInteger(milliseconds) ||
Math.abs(milliseconds) > 8_640_000_000_000_000
) {
throw new RangeError("Timestamp is outside JavaScript Date range");
}
return new Date(milliseconds).toISOString();
}
Parse and validate incoming strings separately. Avoid permissive parsing that silently accepts inputs such as "1780412400invalid".
For human-readable output, select the intended timezone explicitly:
const date = new Date(1780412400 * 1000);
const formatter = new Intl.DateTimeFormat("en-GB", {
timeZone: "Asia/Dhaka",
dateStyle: "medium",
timeStyle: "short",
});
formatter.format(date);
Python
Use a timezone-aware datetime for UTC conversions:
from datetime import datetime, timezone
unix_seconds = 1780412400
# Unix seconds → aware UTC datetime
utc_datetime = datetime.fromtimestamp(
unix_seconds,
tz=timezone.utc,
)
print(utc_datetime.isoformat())
# 2026-06-02T15:00:00+00:00
# Explicitly offset date string → Unix seconds
parsed = datetime.fromisoformat(
"2026-06-02T21:00:00+06:00"
)
print(parsed.timestamp())
# 1780412400.0
Calling datetime.fromtimestamp(value) without tz returns a naive local datetime. Calling .timestamp() on a naive datetime normally interprets it as local time.
datetime.utcnow() returns naive UTC and is deprecated from Python 3.12. Prefer datetime.now(timezone.utc). Python datetime documentation.
For current integer timestamps without an intermediate floating-point conversion:
import time
now_ns = time.time_ns()
unix_seconds = now_ns // 1_000_000_000
unix_milliseconds = now_ns // 1_000_000
time.time_ns() returns an integer in nanoseconds; the actual clock resolution can be coarser. Python time documentation.
SQL
Database functions differ in their timezone assumptions, supported ranges, and return types. Make the session timezone explicit when checking examples.
PostgreSQL
SET TIME ZONE 'UTC';
-- Unix seconds → timestamp with time zone
SELECT to_timestamp(1780412400);
-- 2026-06-02 15:00:00+00
-- An explicit instant → Unix seconds
SELECT EXTRACT(
EPOCH FROM TIMESTAMPTZ '2026-06-02 15:00:00+00'
);
-- Numerically: 1780412400
PostgreSQL’s to_timestamp() accepts epoch seconds and returns timestamp with time zone. Output follows the session timezone. PostgreSQL date/time functions.
For event instants, TIMESTAMPTZ is commonly appropriate. Despite its name, it does not preserve the original timezone name; retain that separately when needed. A DATE or timezone-free timestamp can be appropriate for calendar data that intentionally does not represent an instant. PostgreSQL date/time types.
MySQL
SET time_zone = '+00:00';
-- Unix seconds → UTC calendar representation
SELECT FROM_UNIXTIME(1780412400);
-- 2026-06-02 15:00:00
-- Calendar representation interpreted in the session timezone
SELECT UNIX_TIMESTAMP('2026-06-02 15:00:00');
-- 1780412400
FROM_UNIXTIME() renders in the session timezone, while UNIX_TIMESTAMP(date) interprets its date argument using that timezone. MySQL date/time functions.
Do not assume MySQL TIMESTAMP removes the Year 2038 limit. In MySQL 8.4, its upper boundary is 2038-01-19 03:14:07 UTC. DATETIME supports a broader calendar range but does not perform the same automatic timezone conversion. Choose deliberately between a documented UTC DATETIME convention, an epoch BIGINT field, and other representations appropriate to your application. MySQL 8.4 temporal types.
Linux timestamps: get and convert epoch time
On Linux systems using GNU Coreutils date, these commands cover common conversions:
# Current Unix timestamp in seconds
date +%s
# Unix seconds → UTC date
date -u -d '@1780412400' '+%Y-%m-%dT%H:%M:%SZ'
# 2026-06-02T15:00:00Z
# UTC date → Unix seconds
date -u -d '2026-06-02 15:00:00' +%s
# 1780412400
# Current epoch seconds with a fractional nanosecond field
date +%s.%N
The -u option makes date parsing and display use UTC. The @ prefix identifies an epoch-seconds input.
These are GNU commands. The default macOS/BSD date utility has different conversion options. GNU date examples and output options.
“Linux timestamp” is not a separate epoch format. Always check the field’s meaning and unit: a log timestamp, file timestamp, and application identifier are not interchangeable merely because they contain digits.
What is the maximum Unix timestamp?
There is no universal maximum Unix timestamp. The limit depends on the numeric type, time unit, and date library or database processing the value.
| Representation | Maximum stored value | Resulting upper boundary |
|---|---|---|
| Signed 32-bit seconds | 2147483647 | 2038-01-19T03:14:07Z |
| Unsigned 32-bit seconds | 4294967295 | 2106-02-07T06:28:15Z |
| Signed 64-bit seconds | 9223372036854775807 | Approximately 292 billion years after the epoch, mathematically |
| Signed 64-bit nanoseconds | 9223372036854775807 | 2262-04-11T23:47:16.854775807Z |
JavaScript Date milliseconds | 8640000000000000 | +275760-09-13T00:00:00.000Z |
A numeric field’s mathematical range does not guarantee that a date formatter can handle the corresponding year.
The key distinction is 64-bit seconds versus 64-bit nanoseconds. They have the same integer capacity but radically different date ranges. JavaScript’s separate date boundary is defined by ECMAScript’s time range.
The Year 2038 problem
A signed 32-bit epoch-seconds field cannot represent the second after:
2147483647 → 2038-01-19T03:14:07Z
If a system wraps the value to the signed minimum, it becomes:
-2147483648 → 1901-12-13T20:45:52Z
Wrapping is a possible failure mode, not a universal guarantee. Other operations may reject the value or fail differently; signed arithmetic overflow in C must not be treated as a portable wraparound mechanism.
A complete fix checks the application, libraries, database fields, serialized formats, and external protocols. A 64-bit operating system alone does not prove that every timestamp field is safe. GNU guidance on avoiding Y2038.
How many bytes does a timestamp use?
An explicitly sized 32-bit integer uses 4 bytes; a 64-bit integer uses 8 bytes. A textual timestamp uses its encoded character length plus any surrounding format overhead.
Do not infer storage size from decimal digit count. Also, do not assume time_t has the same width across every target build; its configuration can depend on the platform and C library. GNU C Library time-width configuration.
Unix nanoseconds and JavaScript precision
Contemporary epoch nanoseconds exceed JavaScript’s largest safe Number integer, 9007199254740991. Use BigInt or a documented string representation when exact integer precision matters.
const epochNanoseconds = 1780412400123456789n;
const wholeSeconds = epochNanoseconds / 1_000_000_000n;
const nanosecondRemainder = epochNanoseconds % 1_000_000_000n;
// 1780412400n
// 123456789n
This example uses a positive timestamp. Define quotient and remainder conventions separately if supporting negative values.
For JSON interchange, make the precision contract visible:
{
"unix_nanoseconds": "1780412400123456789"
}
Converting nanoseconds into a JavaScript Date also discards precision finer than milliseconds. ECMAScript numeric and date definitions.
Leap seconds: why Unix time ignores them
Unix/POSIX time does not accumulate leap seconds as additional epoch seconds. Leap days are different: February 29 is included in the calendar calculation.
Consequently, subtracting epoch timestamps is not a universal way to measure exact physical elapsed time across leap-second events.
Systems can handle clock synchronization differently. For example, Google’s leap smear spreads a leap-second adjustment over a period instead of exposing an abrupt insertion. Mixing smeared and unsmeared time sources can therefore introduce temporary differences. Google’s leap-smear documentation.
Use a monotonic clock for durations
A wall clock can be corrected while a program runs. For request timing, benchmarks, and timeouts, use a clock intended for elapsed-time measurement:
import time
start_ns = time.perf_counter_ns()
# Example operation; replace with the work being measured.
result = sum(range(100_000))
elapsed_ns = time.perf_counter_ns() - start_ns
print(elapsed_ns)
The reference point of a performance counter is not the Unix epoch. Its useful output is the difference between readings. Python performance-counter documentation.
Common timestamp bugs (and how to avoid them)
| Symptom | Likely cause | What to check |
|---|---|---|
| A recent event appears in January 1970 | Seconds supplied to a milliseconds API | Producer and consumer units |
| A date appears thousands of years ahead | Milliseconds interpreted as seconds | Conversion applied at the boundary |
| Output differs between laptop and server | Implicit local timezone | Parsing and formatting timezone |
| A daily event shifts by an hour | Fixed-duration arithmetic across DST | Calendar recurrence and named timezone |
| Nanoseconds change after JSON parsing | Integer exceeds consumer precision | String or integer-capable serialization |
| Dates beyond 2038 fail | A restricted field or conversion layer | End-to-end type and range support |
| Epoch zero disappears | 0 treated as false or missing | Explicit null and undefined checks |
| A measured operation has negative duration | Wall-clock correction | Monotonic duration measurement |
Why adding 86,400 seconds may not mean “tomorrow”
Adding 86400 seconds advances by a fixed duration on the epoch scale. It does not express “the same local time on the next calendar date.”
Across daylight-saving transitions, those operations can produce different results. Calendar scheduling requires the local date, intended time, timezone, and a policy for nonexistent or repeated local times.
Similarly, two machines can produce out-of-order event timestamps if their clocks disagree. Where ordering matters, define an ordering mechanism rather than relying solely on wall-clock values.
Frequently asked questions
Can a Unix timestamp be negative?
Many APIs use negative values for dates before 1970: -1 commonly represents 1969-12-31T23:59:59Z.
Support is implementation-specific. POSIX’s calendar relationship does not define negative values, so verify the actual parser, database, and operating-system behavior before relying on them.
What is the date for Unix timestamp 1725151258?
Interpreted as seconds, it is September 1, 2024, at 00:40:58 UTC: 2024-09-01T00:40:58Z. Its millisecond equivalent is 1725151258000.
Is a Unix timestamp always UTC?
Its epoch is defined in UTC, but the numeric value has no stored timezone. The same value can be displayed in UTC, Dhaka, Tokyo, or another zone without changing the instant it represents.
Is epoch time the same as Unix time?
Usually, in Unix-oriented APIs. However, an epoch is simply a reference origin. Confirm both the origin and unit when integrating with an unfamiliar system.
Can I use a timestamp as a unique ID?
Not safely by itself. Multiple events can occur within the same clock tick, and different machines can generate identical values. Use a dedicated identifier or a scheme explicitly designed for uniqueness.
TL;DR
Before accepting or emitting a timestamp, document:
- Origin: Unix epoch or another reference?
- Unit: Seconds, milliseconds, microseconds, or nanoseconds?
- Precision: Integer, fractional value, or decimal string?
- Range: Which dates do all connected systems support?
- Timezone handling: How are calendar inputs interpreted and outputs displayed?
- Meaning: An instant, duration, date-only value, or recurring schedule?
Use the timestamp converter for contemporary epoch examples, the time zone converter for local displays, and the converter tools directory for related utilities.
Found an incorrect example or platform-specific difference? Send a correction to Toolk with the input, expected output, and relevant runtime or database version.
Keep reading
Related posts
Words to Pages: Estimates for 500, 1000 and 2000 Words
Estimate pages from word count using explicit layout assumptions. Compare examples and learn when spacing, fonts, margins, tables, and images change the result.
Read postSales Tax and VAT Calculations: Add and Extract Tax
Calculate tax from a net price or extract it from a total. Compare formulas, rounding, and jurisdiction-specific rules that a calculation cannot determine.
Read postRoman Numeral Rules: Symbols, Subtraction and Examples
Learn modern Roman numeral rules, invalid forms, and worked conversions. Distinguish the standard converter range from historical numeral variations.
Read post