Unix Timestamps Explained: What They Are and How to Convert Them
This guide has a free tool → Open JWT Decoder
Unix Timestamps Explained: What They Are and How to Convert Them
A Unix timestamp (also called epoch time or POSIX time) is the number of seconds that have elapsed since January 1, 1970, at 00:00:00 UTC. This moment is called the Unix epoch. It is the universal clock that nearly every computer system, programming language, and API relies on when it needs to represent a specific moment in time.
For example:
0= January 1, 1970, 00:00:00 UTC1000000000= September 9, 2001, 01:46:40 UTC1700000000= November 14, 2023, 22:13:20 UTC
Right now, the Unix timestamp is a 10-digit number somewhere around 1.77 billion. By the end of 2033, it will cross the 2 billion mark.
JWT Decoder
Free online JWT decoder - decode and inspect JSON Web Tokens without sending them to a server
Timestamp Converter
Free online timestamp converter - convert between Unix timestamps and human-readable dates instantly
Cron Expression Parser
Free online cron expression parser - parse cron expressions and see the next scheduled run times
Why January 1, 1970?
The Unix epoch was established in the early days of Unix development at Bell Labs. The 1970 date was chosen largely because it was recent enough to be practical and because the early Unix systems had limited storage for timestamps. It was not a particularly meaningful date --- it was simply convenient for the engineers who designed the system.
Some systems use different epochs. GPS time begins at January 6, 1980. Microsoft's FILETIME format starts at January 1, 1601. Apple's Core Data uses January 1, 2001. When integrating with systems that use different epochs, you need to account for the offset, which is another reason that understanding your timestamp format matters.
Why Do Developers Use Timestamps?
Timestamps solve several fundamental problems that human-readable date strings create.
Timezone independence. A timestamp is always UTC. There is no ambiguity about which timezone "March 15, 2026 3:00 PM" refers to. The timestamp 1773849600 means exactly one moment in time, everywhere on earth, for every system.
Easy arithmetic. Want to know how many seconds elapsed between two events? Subtract one timestamp from another. Want to add 24 hours to a time? Add 86400. Want to find all records from the last 7 days? Compare against now - 604800. Date arithmetic with human-readable formats requires handling months with different lengths, leap years, daylight saving time, and timezone transitions --- all of which are sources of bugs.
Language agnostic. Every programming language can work with Unix timestamps natively. JSON APIs, databases, log files, and scheduled tasks all use them because they are universally understood. A Python service, a JavaScript frontend, and a Go microservice all agree on what a timestamp means without any negotiation.
Sorting and comparison. Timestamps sort correctly as plain numbers. You do not need date parsing libraries to determine whether one event happened before another. A simple > or < comparison works.
Compact storage. A Unix timestamp takes 4 to 8 bytes to store as an integer. A formatted date string like "November 14, 2023 at 10:13:20 PM UTC" takes over 40 bytes. In a database with millions of records, this difference adds up.
Common Timestamp Formats
This is where confusion enters. Not all timestamps represent seconds since epoch.
| Format | Digits | Example | Used by |
|---|---|---|---|
| Seconds | 10 | 1700000000 | Unix, PHP, Python, Ruby, Go |
| Milliseconds | 13 | 1700000000000 | JavaScript, Java, AWS Lambda |
| Microseconds | 16 | 1700000000000000 | PostgreSQL, high-precision logging |
| Nanoseconds | 19 | 1700000000000000000 | Go's time.UnixNano, some databases |
| ISO 8601 | variable | 2023-11-14T22:13:20Z | REST APIs, JSON (not a numeric timestamp) |
The single most common mistake: JavaScript uses milliseconds, while most other languages and systems use seconds. If you call new Date(1700000000) in JavaScript, you get a date in January 1970 --- because JavaScript interprets that as 1.7 billion milliseconds (roughly 19 days after epoch), not 1.7 billion seconds. The correct call is new Date(1700000000 * 1000).
Going the other direction, if you take a JavaScript timestamp (Date.now() returns milliseconds) and store it as seconds in a database or API, you will end up with a year in the year 57000-something. This is an extremely common bug in applications that mix JavaScript frontends with server backends.
How to Identify a Timestamp's Unit
A quick heuristic based on the number of digits in 2026:
- 10 digits: seconds (1.7x billion range is valid for 2026)
- 13 digits: milliseconds
- 16 digits: microseconds
- 19 digits: nanoseconds
If a timestamp gives you a year in the 1970s when you expect recent dates, you are probably treating milliseconds as seconds. If it gives you a year tens of thousands in the future, you are probably treating seconds as milliseconds.
Converting Timestamps in JavaScript
JavaScript's Date object is the primary tool for timestamp work in the browser and in Node.js. Note carefully that JavaScript always works in milliseconds.
// Get current timestamp in seconds (like Unix timestamp)
const nowSeconds = Math.floor(Date.now() / 1000);
console.log(nowSeconds); // e.g., 1771200000
// Get current timestamp in milliseconds (JavaScript native)
const nowMs = Date.now();
console.log(nowMs); // e.g., 1771200000000
// Convert seconds timestamp to Date object
const date = new Date(1700000000 * 1000);
console.log(date.toISOString()); // "2023-11-14T22:13:20.000Z"
// Convert Date object to seconds timestamp
const timestamp = Math.floor(new Date("2026-03-15T00:00:00Z").getTime() / 1000);
console.log(timestamp); // 1773878400
// Format a timestamp as a readable string
function formatTimestamp(seconds) {
return new Date(seconds * 1000).toLocaleString("en-US", {
timeZone: "UTC",
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
}
// Calculate time difference
function secondsAgo(timestamp) {
return Math.floor(Date.now() / 1000) - timestamp;
}
// Add N hours to a timestamp
function addHours(timestamp, hours) {
return timestamp + hours * 3600;
}
// Check if a timestamp is in the past
function isExpired(timestamp) {
return timestamp < Math.floor(Date.now() / 1000);
}Converting Timestamps in Python
Python's datetime and time modules handle timestamp conversions cleanly. Python 3.3+ added datetime.timestamp(), which is the preferred modern approach.
import time
import datetime
from datetime import timezone
# Current timestamp (seconds since epoch)
now = int(time.time())
print(now) # e.g., 1771200000
# Current timestamp using datetime (timezone-aware)
now_aware = datetime.datetime.now(timezone.utc).timestamp()
# Convert timestamp to datetime (local timezone)
dt_local = datetime.datetime.fromtimestamp(1700000000)
print(dt_local) # Local time representation
# Convert timestamp to UTC datetime
dt_utc = datetime.datetime.fromtimestamp(1700000000, tz=timezone.utc)
print(dt_utc) # 2023-11-14 22:13:20+00:00
print(dt_utc.isoformat()) # "2023-11-14T22:13:20+00:00"
# Convert datetime string to timestamp
dt = datetime.datetime(2026, 3, 15, 0, 0, 0, tzinfo=timezone.utc)
ts = int(dt.timestamp())
print(ts) # 1773878400
# Parse ISO 8601 string to timestamp
from datetime import datetime
dt_parsed = datetime.fromisoformat("2026-03-15T00:00:00+00:00")
ts_parsed = int(dt_parsed.timestamp())
# Add N days to a timestamp
def add_days(timestamp, days):
return timestamp + days * 86400
# Calculate difference in hours
def hours_between(ts1, ts2):
return abs(ts1 - ts2) / 3600Converting Timestamps in PHP
PHP's date and time functions have been around since PHP 4. The DateTime class (PHP 5+) provides an object-oriented interface that handles edge cases better than the older procedural functions.
<?php
// Current timestamp (seconds)
$now = time();
echo $now; // e.g., 1771200000
// Timestamp to human-readable string
echo date('Y-m-d H:i:s', 1700000000); // "2023-11-14 22:13:20"
echo date('D, d M Y H:i:s T', 1700000000); // "Tue, 14 Nov 2023 22:13:20 UTC"
// Date string to timestamp
$ts = strtotime('2026-03-15 00:00:00 UTC');
echo $ts; // 1773878400
// Using DateTime class (preferred)
$dt = new DateTime('2026-03-15', new DateTimeZone('UTC'));
$ts = $dt->getTimestamp();
// Timestamp to DateTime object
$dt = new DateTime();
$dt->setTimestamp(1700000000);
echo $dt->format('Y-m-d H:i:s'); // "2023-11-14 22:13:20"
// Add 7 days using DateInterval
$dt = new DateTime('@1700000000');
$dt->add(new DateInterval('P7D'));
echo $dt->getTimestamp();
// Check if expired
function isExpired($timestamp) {
return $timestamp < time();
}Converting Timestamps in Go
Go's time package treats time as first-class. The time.Unix() function creates a time.Time value from a Unix timestamp.
package main
import (
"fmt"
"time"
)
func main() {
// Current timestamp (seconds)
now := time.Now().Unix()
fmt.Println(now) // e.g., 1771200000
// Current timestamp (milliseconds)
nowMs := time.Now().UnixMilli()
// Current timestamp (nanoseconds)
nowNs := time.Now().UnixNano()
// Timestamp to time.Time
t := time.Unix(1700000000, 0).UTC()
fmt.Println(t.Format(time.RFC3339)) // "2023-11-14T22:13:20Z"
// time.Time to timestamp
ts := time.Date(2026, 3, 15, 0, 0, 0, 0, time.UTC).Unix()
fmt.Println(ts) // 1773878400
// Parse ISO 8601 string
parsed, _ := time.Parse(time.RFC3339, "2026-03-15T00:00:00Z")
fmt.Println(parsed.Unix())
// Add 24 hours
future := time.Unix(now, 0).Add(24 * time.Hour).Unix()
// Check if expired
isExpired := func(ts int64) bool {
return ts < time.Now().Unix()
}
_ = nowMs
_ = nowNs
_ = future
_ = isExpired
}Converting Timestamps in SQL
Databases have their own timestamp functions. Here are the most common patterns for MySQL and PostgreSQL.
-- MySQL
-- Current timestamp as integer
SELECT UNIX_TIMESTAMP() AS current_ts;
-- Timestamp integer to datetime
SELECT FROM_UNIXTIME(1700000000) AS readable_date;
-- Result: "2023-11-14 22:13:20"
-- Datetime to timestamp integer
SELECT UNIX_TIMESTAMP('2026-03-15 00:00:00') AS ts;
-- Find records from last 7 days
SELECT * FROM events
WHERE created_at > UNIX_TIMESTAMP(NOW() - INTERVAL 7 DAY);
-- PostgreSQL
-- Current timestamp as integer
SELECT EXTRACT(EPOCH FROM NOW())::INTEGER AS current_ts;
-- Timestamp integer to timestamptz
SELECT TO_TIMESTAMP(1700000000) AT TIME ZONE 'UTC' AS readable_date;
-- Datetime to timestamp integer
SELECT EXTRACT(EPOCH FROM '2026-03-15 00:00:00+00'::TIMESTAMPTZ)::INTEGER;
-- Find records from last 7 days
SELECT * FROM events
WHERE created_at > NOW() - INTERVAL '7 days';Common Date Arithmetic with Timestamps
One of the main advantages of working with timestamps is that time arithmetic is just integer arithmetic. Here is a reference for common time units in seconds:
| Unit | Seconds |
|---|---|
| 1 minute | 60 |
| 5 minutes | 300 |
| 15 minutes | 900 |
| 1 hour | 3,600 |
| 6 hours | 21,600 |
| 12 hours | 43,200 |
| 1 day | 86,400 |
| 1 week | 604,800 |
| 30 days | 2,592,000 |
| 365 days | 31,536,000 |
| 366 days (leap year) | 31,622,400 |
Be careful with month-based arithmetic. Months are not a fixed number of seconds --- they vary between 28 and 31 days. For "add one month," use your language's date library rather than adding a fixed number of seconds.
Displaying Relative Time
Relative timestamps ("3 minutes ago", "2 days ago") are common in web applications. Here is a JavaScript implementation:
function timeAgo(timestamp) {
const seconds = Math.floor(Date.now() / 1000) - timestamp;
const intervals = [
{ label: "year", seconds: 31536000 },
{ label: "month", seconds: 2592000 },
{ label: "week", seconds: 604800 },
{ label: "day", seconds: 86400 },
{ label: "hour", seconds: 3600 },
{ label: "minute", seconds: 60 },
{ label: "second", seconds: 1 },
];
for (const interval of intervals) {
const count = Math.floor(seconds / interval.seconds);
if (count >= 1) {
return `${count} ${interval.label}${count !== 1 ? "s" : ""} ago`;
}
}
return "just now";
}
// Usage
timeAgo(Math.floor(Date.now() / 1000) - 90); // "1 minute ago"
timeAgo(Math.floor(Date.now() / 1000) - 7200); // "2 hours ago"
timeAgo(Math.floor(Date.now() / 1000) - 90000); // "1 day ago"Handling Timezones Correctly
Timestamps themselves are always UTC --- the timezone issue only arises when you display them. Here are the rules:
Rule 1: Store timestamps in UTC. Always. Never store local time as a timestamp.
Rule 2: Convert to local time at display time. Do the conversion in the user's browser using their local timezone, or on the server if you know the user's timezone preference.
Rule 3: Be explicit about timezone when parsing strings. new Date("2026-03-15") in JavaScript treats this as midnight UTC. new Date("2026-03-15T00:00:00") (no Z) treats it as midnight local time. These are different moments in time.
// Safe: always specify UTC
const ts = new Date("2026-03-15T00:00:00Z").getTime() / 1000;
// Risky: behavior depends on user's timezone
const ts2 = new Date("2026-03-15").getTime() / 1000;
// Display in user's local timezone
const localDate = new Date(1700000000 * 1000).toLocaleString();
// Display in a specific timezone
const options = {
timeZone: "America/New_York",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
};
const nyDate = new Date(1700000000 * 1000).toLocaleString("en-US", options);Daylight Saving Time and Timestamps
Timestamps sidestep daylight saving time (DST) entirely because they are in UTC, which never observes DST. The problem only appears when converting between timestamps and local time, because the UTC offset changes twice a year.
For example, "2:30 AM on March 8, 2026 in New York" does not exist --- the clock jumps from 2:00 AM directly to 3:00 AM when DST begins. Any code that tries to create a Date object at that exact local time will silently create a time that is off by an hour.
Similarly, "1:30 AM on November 1, 2026 in New York" happens twice --- once during DST (UTC-4) and once after the clock falls back (UTC-5). If you are storing scheduled task times or calendar events in local time, you will have bugs during DST transitions.
The solution: store timestamps in UTC, convert to local time only for display.
The Year 2038 Problem
Unix timestamps stored as 32-bit signed integers will overflow on January 19, 2038, at 03:14:07 UTC. After that moment, the counter wraps around to a negative number, which systems interpret as December 13, 1901. This is known as the Y2K38 problem or the Year 2038 Problem.
To understand why: a 32-bit signed integer can hold values from -2,147,483,648 to 2,147,483,647. The maximum value, 2,147,483,647, corresponds to January 19, 2038, at 03:14:07 UTC. One second later, the counter overflows to -2,147,483,648, which represents December 13, 1901.
This is a real concern for:
- Embedded systems and IoT devices that use 32-bit integers for timestamps
- Legacy databases with INT (32-bit) columns storing Unix timestamps
- Older operating systems on 32-bit hardware
- Firmware that has not been updated in decades
- BIOS and hardware real-time clocks on 32-bit systems
Are modern web applications safe? For the most part, yes. Modern 64-bit operating systems use 64-bit timestamps, which will not overflow for roughly 292 billion years. Most modern databases (PostgreSQL, MySQL 8+, SQLite) use 64-bit types for timestamp storage. JavaScript, Python, and most modern runtimes are also safe.
However, if you are working with legacy databases that have INT(11) or INTEGER columns (32-bit) storing Unix timestamps, you should migrate those columns to BIGINT before 2038. That seems distant, but the applications you write today may still be running then.
Negative Timestamps
Unix timestamps can be negative, representing dates before January 1, 1970. Most languages and databases support this.
| Timestamp | Date |
|---|---|
| -2208988800 | January 1, 1900, 00:00:00 UTC |
| -1000000000 | September 9, 1938, 01:46:40 UTC |
| -86400 | December 31, 1969, 00:00:00 UTC |
| -1 | December 31, 1969, 23:59:59 UTC |
| 0 | January 1, 1970, 00:00:00 UTC |
Negative timestamps are valid and should work in any modern system. They are commonly needed when working with historical data, such as birthdate fields, historical records, or any dates before 1970.
Quick Reference: Important Timestamps
| Timestamp | Date |
|---|---|
| 0 | Jan 1, 1970 00:00:00 UTC (Unix epoch) |
| 1000000000 | Sep 9, 2001 01:46:40 UTC |
| 1234567890 | Feb 13, 2009 23:31:30 UTC |
| 1500000000 | Jul 14, 2017 02:40:00 UTC |
| 1700000000 | Nov 14, 2023 22:13:20 UTC |
| 1800000000 | Jan 18, 2027 03:06:40 UTC |
| 2000000000 | May 18, 2033 03:33:20 UTC |
| 2147483647 | Jan 19, 2038 03:14:07 UTC (32-bit max) |
| 4102444800 | Jan 1, 2100 00:00:00 UTC |
Working with Timestamps in APIs
When consuming REST APIs, you will encounter timestamps in various formats. Here is how to handle them:
// API returns Unix seconds timestamp
async function fetchEvent(id) {
const response = await fetch(`/api/events/${id}`);
const data = await response.json();
// Convert seconds to Date object
const createdAt = new Date(data.created_at * 1000);
const updatedAt = new Date(data.updated_at * 1000);
return {
...data,
createdAt,
updatedAt,
isExpired: data.expires_at < Math.floor(Date.now() / 1000),
};
}
// Sending timestamps to an API
async function createEvent(title, expiresInHours) {
const now = Math.floor(Date.now() / 1000);
const expiresAt = now + expiresInHours * 3600;
const response = await fetch("/api/events", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
title,
created_at: now,
expires_at: expiresAt,
}),
});
return response.json();
}Timestamps in JWT Tokens
JSON Web Tokens use Unix timestamps for their time-based claims. Understanding timestamp format is essential when working with JWTs.
{
"sub": "user_12345",
"iat": 1700000000,
"exp": 1700086400,
"nbf": 1700000000
}The three time-related claims are:
iat(issued at): when the token was createdexp(expiration): when the token becomes invalidnbf(not before): earliest time the token is valid
All three use Unix seconds timestamps. The exp value above (1700086400) is exactly 86,400 seconds (one day) after iat (1700000000), so this token has a 24-hour lifetime.
You can use the JWT Decoder to inspect these claims and see them as human-readable dates. You can also use the Timestamp Converter to convert any claim value to a readable date.
Cron Jobs and Timestamps
Scheduled tasks and cron jobs frequently interact with timestamps. A common pattern is running a job that processes records created within the last time window:
#!/bin/bash
# Run this cron job every hour
# 0 * * * * /path/to/this-script.sh
# Get timestamp for 1 hour ago
ONE_HOUR_AGO=$(date -d "1 hour ago" +%s)
# Process records newer than one hour ago
psql -c "
SELECT process_record(id)
FROM pending_records
WHERE created_at > $ONE_HOUR_AGO
AND created_at <= $(date +%s)
"Learn more about scheduling with the Cron Parser, which translates cron expressions into plain English.
Convert Timestamps with ToolBox
The Timestamp Converter on ToolBox lets you:
- Convert any Unix timestamp (seconds or milliseconds) to a human-readable date instantly
- Convert any date and time back to a Unix timestamp
- See the current Unix timestamp updating in real time
- Switch between seconds and milliseconds display
- Convert across any timezone --- not just UTC
- Handle negative timestamps for pre-1970 dates
The tool runs entirely in your browser. Nothing is sent to any server, and you do not need an account to use it.
Paste a timestamp like 1700000000 and see immediately that it corresponds to November 14, 2023 at 10:13 PM UTC. Or type in a date and see the Unix timestamp you should use in your code.
Developers who work with APIs, databases, JWT tokens, or log files will use a timestamp converter regularly. Bookmark it now.
---
Related Tools
Free, private, no signup required
JSON Formatter
JSON formatter and validator online - format, beautify, and validate JSON data instantly in your browser
Regex Tester
Free online regex tester - test and debug regular expressions with live matching and highlights
Text Diff Checker
Free online text diff checker - compare two texts and see the differences highlighted line by line
Code Formatter
Free online code formatter - beautify and format JavaScript, CSS, HTML, and more
You might also like
Want higher limits, batch processing, and AI tools?