Skip to main content

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.

MM H TawfikPublished Updated 14 min read

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?

TermMeaning
Unix epochThe reference instant: 1970-01-01T00:00:00Z.
Unix timeA numeric representation of time relative to the Unix epoch.
Unix timestampA particular value in that representation, such as 1780412400 seconds.
POSIX timeThe standardized seconds-since-the-epoch representation commonly associated with Unix time.
Epoch timeOften means Unix time, but “epoch” alone does not identify a particular origin or unit.
Epoch secondsA count expressed in seconds; confirm which epoch the system uses.
UTCThe 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 secondsUTC date and timeMeaning
-11969-12-31T23:59:59ZOne second before the epoch, where supported
01970-01-01T00:00:00ZThe Unix epoch
11970-01-01T00:00:01ZOne second after the epoch
864001970-01-02T00:00:00ZStart of the next UTC calendar day
10000000002001-09-09T01:46:40ZFirst 10-digit positive epoch-seconds value
12345678902009-02-13T23:31:30ZSequential-digit reference value
17251512582024-09-01T00:40:58ZA worked timestamp-to-date example
17804124002026-06-02T15:00:00ZThe example used throughout this guide
21474836472038-01-19T03:14:07ZSigned 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:

UnitUnits per secondExample value
Seconds11780412400
Milliseconds10001780412400000
Microseconds10000001780412400000000
Nanoseconds10000000001780412400000000000

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.

RepresentationMaximum stored valueResulting upper boundary
Signed 32-bit seconds21474836472038-01-19T03:14:07Z
Unsigned 32-bit seconds42949672952106-02-07T06:28:15Z
Signed 64-bit seconds9223372036854775807Approximately 292 billion years after the epoch, mathematically
Signed 64-bit nanoseconds92233720368547758072262-04-11T23:47:16.854775807Z
JavaScript Date milliseconds8640000000000000+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)

SymptomLikely causeWhat to check
A recent event appears in January 1970Seconds supplied to a milliseconds APIProducer and consumer units
A date appears thousands of years aheadMilliseconds interpreted as secondsConversion applied at the boundary
Output differs between laptop and serverImplicit local timezoneParsing and formatting timezone
A daily event shifts by an hourFixed-duration arithmetic across DSTCalendar recurrence and named timezone
Nanoseconds change after JSON parsingInteger exceeds consumer precisionString or integer-capable serialization
Dates beyond 2038 failA restricted field or conversion layerEnd-to-end type and range support
Epoch zero disappears0 treated as false or missingExplicit null and undefined checks
A measured operation has negative durationWall-clock correctionMonotonic 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:

  1. Origin: Unix epoch or another reference?
  2. Unit: Seconds, milliseconds, microseconds, or nanoseconds?
  3. Precision: Integer, fractional value, or decimal string?
  4. Range: Which dates do all connected systems support?
  5. Timezone handling: How are calendar inputs interpreted and outputs displayed?
  6. 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.