A Unix timestamp is a compact numeric way to identify a single moment in time. Instead of storing a formatted date such as 2026-08-04 21:30:00, a Unix timestamp stores the number of seconds that have elapsed since January 1, 1970 at 00:00:00 UTC. That starting point is called the Unix epoch.
Developers use Unix timestamps because they are easy to compare, sort, transmit, index, and store. A timestamp is just a number, so databases can order it quickly, APIs can move it without locale-specific formatting issues, and applications can convert it into a human-friendly date only at the edge of the system. That is why epoch time appears in logs, authentication tokens, analytics events, scheduled jobs, cache expiration, payment webhooks, database records, and almost every programming language's date/time APIs.
Unix timestamp definition
A Unix timestamp is the count of elapsed time from the Unix epoch. In the traditional definition, the count is measured in whole seconds. For example, the timestamp 0 means 1970-01-01T00:00:00Z. The timestamp 60 means sixty seconds after that moment. The timestamp 1700000000 represents a later instant in UTC, and any local date display is simply a formatting choice.
The important detail is that a timestamp does not include a timezone, a calendar format, a month name, or a human language. It is an absolute instant. When a user in New York, London, and Tokyo views the same timestamp, they are viewing the same moment, but their local clocks may display different wall times. This is exactly what makes timestamps useful: the stored value stays stable while the presentation changes based on context.
In everyday web development, the phrase "Unix timestamp" can sometimes be used loosely. Some APIs say "timestamp" while returning milliseconds. Some databases store microseconds. Some event systems use nanoseconds. The concept is the same, but the unit changes the number dramatically. Always confirm the unit before saving, comparing, or converting a value.
Why the epoch starts in 1970
The Unix epoch begins at midnight UTC on January 1, 1970 because early Unix systems needed a simple numeric reference point for representing time. The date was close to the era when Unix was being developed, and it gave systems a practical baseline for counting forward. The epoch is not a historical or astronomical beginning of time; it is a computing convention.
Using a fixed baseline solved a very practical problem. Computers need to compare dates constantly. A filesystem needs to know which file was modified later. A scheduler needs to know whether a job should run now. A cache needs to know whether a value has expired. If dates were stored only as strings such as Jan 2, 2026 or 02/01/2026, comparisons would be fragile because formats vary by language and country. Counting seconds from one agreed moment gives every system a common measuring stick.
The epoch also makes arithmetic straightforward. If an access token expires in one hour, you can add 3600 seconds. If a log entry is newer than another one, the larger timestamp happened later. If a rate limit should reset at a known time, the server can compare the current epoch value with the reset value. The simplicity is the point.
Unix timestamps and UTC
Unix timestamps are tied to UTC, not to a local timezone. UTC stands for Coordinated Universal Time and is the standard reference used for civil timekeeping. When you convert a timestamp into a displayed date, you can choose UTC or a local timezone, but the timestamp number itself does not change.
This distinction prevents a common bug: treating a timestamp as if it were already in the user's timezone. Suppose an API returns 1717243200. That number represents one instant. If your application displays it in UTC, you get one calendar time. If it displays it in America/New_York, you get another. If it displays it in Asia/Kolkata, you get another. None of those conversions should mutate the stored timestamp.
A good mental model is to store instants in UTC and format dates only at the user interface boundary. Backend services, database records, and event streams should avoid local timezone assumptions unless the business rule specifically depends on a local calendar. For example, "send this notification exactly 24 hours from now" can use an instant. "Send this notification at 9:00 AM in the user's city" needs a timezone-aware local date and time.
Seconds vs milliseconds
The most common Unix timestamp bug is mixing seconds and milliseconds. Traditional Unix timestamps are measured in seconds. JavaScript's Date constructor, however, expects milliseconds. That means this code is wrong if createdAt is a seconds timestamp:
const createdAt = 1717243200;
const date = new Date(createdAt); // Wrong: interpreted as milliseconds in 1970
The correct JavaScript conversion multiplies by 1000:
const createdAt = 1717243200;
const date = new Date(createdAt * 1000);
console.log(date.toISOString());
You can often identify the unit by digit length. A present-day seconds timestamp usually has 10 digits. A present-day milliseconds timestamp usually has 13 digits. This is a useful debugging clue, not a permanent rule. Timestamps grow over time, and older or future values may have different lengths. The reliable solution is to read the API documentation, name variables clearly, and validate units at boundaries.
Use names such as expiresAtUnixSeconds, createdAtMs, or eventTimeMicroseconds when a value crosses a service boundary. A little verbosity prevents expensive production bugs, especially when multiple languages are involved.
Negative Unix timestamps
Unix timestamps can be negative. A negative timestamp represents a moment before the Unix epoch. For example, -1 means one second before 1970-01-01T00:00:00Z, which is 1969-12-31T23:59:59Z.
Negative values matter when applications deal with birth dates, historical archives, legal records, imported spreadsheets, or backfilled datasets. Not every platform handles negative timestamps the same way, especially older systems and databases, so test before assuming support. If you are building a public API, document whether negative timestamps are accepted and what range is valid.
For most modern server-side languages and databases, negative timestamp support is available when using mature datetime libraries and appropriate storage types. The trouble usually appears when values are forced into unsigned integers, narrow columns, or client-side libraries that were only tested with recent dates.
Developer examples
Every language has its own date/time API, but the conversion pattern is consistent: decide whether the timestamp is seconds or milliseconds, create a datetime object from the instant, then format it for the desired timezone.
JavaScript
const unixSeconds = 1717243200;
const date = new Date(unixSeconds * 1000);
console.log(date.toISOString());
console.log(Math.floor(Date.now() / 1000));
JavaScript stores timestamps internally as milliseconds. Use Date.now() for milliseconds and divide by 1000 when you need Unix seconds.
PHP
$unixSeconds = 1717243200;
$date = (new DateTimeImmutable('@' . $unixSeconds))
->setTimezone(new DateTimeZone('UTC'));
echo $date->format(DateTimeInterface::ATOM);
echo time();
The @ prefix tells PHP to create the datetime from a Unix timestamp. Set the timezone explicitly before formatting so the output is predictable.
Python
from datetime import datetime, timezone
unix_seconds = 1717243200
dt = datetime.fromtimestamp(unix_seconds, tz=timezone.utc)
print(dt.isoformat())
print(int(datetime.now(tz=timezone.utc).timestamp()))
Prefer timezone-aware datetime objects in Python. Naive datetimes can work locally but often become ambiguous when data moves across services.
MySQL
SELECT FROM_UNIXTIME(1717243200) AS local_time;
SELECT UNIX_TIMESTAMP('2024-06-01 12:00:00') AS unix_seconds;
Database timezone settings can affect formatted output. For portable application logic, store UTC instants and be deliberate about connection timezone settings.
Common mistakes when working with timestamps
The first mistake is treating formatted date strings as if they are safer than timestamps. Strings are excellent for display and interchange when using a standard such as ISO 8601, but arbitrary strings can hide timezone and locale assumptions. A value like 03/04/2026 can mean March 4 or April 3 depending on the reader. A timestamp avoids that ambiguity for instant-based events.
The second mistake is assuming every date/time problem should be represented as a Unix timestamp. A timestamp represents an instant. Some business concepts are not instants. A birthday, for example, is usually a calendar date, not a specific moment in UTC. A store opening time such as "9:00 AM every Monday in Chicago" is a local recurring time rule. If you collapse those concepts into timestamps too early, daylight saving time and timezone changes can create surprising behavior.
The third mistake is storing timestamps in columns that are too small. Signed 32-bit integers run out at 2038-01-19T03:14:07Z. If your application could still be running then, or if it stores future scheduled events, use 64-bit integers or database datetime types designed for the range you need. This matters for embedded systems, older databases, and schema migrations copied from old examples.
The fourth mistake is converting repeatedly. If one service converts UTC to local time, another service parses that local string, and a third service converts it again, drift and ambiguity can creep in. Keep the original instant as the source of truth and format it as late as possible.
Best practices for storing and exchanging epoch time
Use UTC for backend storage unless there is a clear reason not to. This keeps event ordering stable across regions and makes logs easier to compare. When you need to display local time, use the user's timezone at render time. When you need to schedule around a local civil time, store the timezone identifier along with the local rule.
Document timestamp units in every API contract. A field named timestamp is not enough. A field named created_at_unix_seconds or documentation that says "Unix timestamp in seconds" removes guesswork. When returning JSON, consider ISO 8601 strings for readability and timestamps for numeric comparisons, but be consistent. Many APIs provide both when developer ergonomics matter.
Validate timestamps at the boundary of your application. Reject values that are too large, too small, not numeric, or clearly in the wrong unit. For example, if an endpoint expects seconds and receives a 13-digit number, the server can return a helpful validation error instead of silently storing a date thousands of years in the future.
Use reliable date/time libraries for timezone conversion. Timezones change because governments change rules. Hard-coding offsets such as -0500 for a region that observes daylight saving time will eventually fail. Use IANA timezone names such as America/New_York, Europe/London, or Asia/Kolkata when local civil time matters.
Finally, test time-related code with boundary cases. Include the Unix epoch, leap days, daylight saving transitions, negative timestamps if your domain allows them, far-future dates, and milliseconds-vs-seconds inputs. Time bugs are often quiet until a billing cycle, token expiration, calendar invite, or analytics report exposes them.
FAQ
Is a Unix timestamp always in UTC?
A Unix timestamp represents elapsed time from the UTC epoch, so the number itself is timezone-independent. Timezones only matter when you format that number as a calendar date and time.
Why do JavaScript timestamps have 13 digits?
JavaScript Date values use milliseconds since the Unix epoch. Traditional Unix timestamps use seconds. A current seconds timestamp has 10 digits, while a milliseconds timestamp usually has 13 digits.
Can Unix timestamps represent dates before 1970?
Yes. Dates before 1970-01-01 00:00:00 UTC are represented with negative timestamps, as long as the programming language, database, and storage type support them.
What is the Year 2038 problem?
The Year 2038 problem affects systems that store Unix timestamps in signed 32-bit integers. Those values overflow after 2038-01-19 03:14:07 UTC. Modern systems should use 64-bit integers or proper datetime types.