Behind almost every “created at” field, log line, API response and cookie expiry, there’s a plain integer: the Unix timestamp. It’s the simplest way for computers to agree on a moment in time, regardless of time zone, language or calendar. This guide explains what the number means, how to convert it reliably, the classic bugs (milliseconds, time zones, 2038) and how cron uses time to schedule jobs. Paste any timestamp into our Unix timestamp converter to see it as a date.
What a Unix timestamp is
Unix time (also called epoch time or POSIX time) counts seconds since 00:00:00 UTC on Thursday, 1 January 1970, the “Unix epoch”.
| Timestamp | UTC date and time |
|---|---|
0 |
1970-01-01 00:00:00 |
1000000000 |
2001-09-09 01:46:40 |
1791417600 |
2026-10-08 00:00:00 |
1800000000 |
2027-01-15 08:00:00 |
2147483647 |
2038-01-19 03:14:07 |
Dates before 1970 are negative numbers. Unix time ignores leap seconds: every day is treated as exactly 86,400 seconds.
Why developers like it
- Time-zone-free: one number represents the same instant everywhere.
- Easy arithmetic: add 3,600 for an hour, 86,400 for a day.
- Sortable and compact: compare two integers instead of parsing date strings.
Seconds vs milliseconds (and more)
| Unit | Digits today | Example | Used by |
|---|---|---|---|
| Seconds | 10 | 1791460800 |
Unix/Linux, PHP, Python time.time() (float), most APIs |
| Milliseconds | 13 | 1791460800000 |
JavaScript, Java, many JSON APIs |
| Microseconds | 16 | 1791460800000000 |
PostgreSQL internals, some logging |
| Nanoseconds | 19 | 1791460800000000000 |
Go UnixNano, high-resolution tracing |
The most common bug is treating milliseconds as seconds, which produces a date tens of thousands of years in the future, or the reverse, which produces a date in January 1970.
Converting in code
// JavaScript (milliseconds)
const now = Math.floor(Date.now() / 1000); // seconds
const d = new Date(1791460800 * 1000);
d.toISOString(); // "2026-10-08T12:00:00.000Z"
d.toLocaleString("en-GB", { timeZone: "Europe/London" });
# Python
from datetime import datetime, timezone
datetime.fromtimestamp(1791460800, tz=timezone.utc) # 2026-10-08 12:00:00+00:00
int(datetime.now(timezone.utc).timestamp())
# Shell
date +%s # current timestamp
date -u -d @1791460800 # GNU/Linux
date -u -r 1791460800 # macOS/BSD
-- PostgreSQL
SELECT to_timestamp(1791460800);
SELECT extract(epoch FROM now());
-- MySQL
SELECT FROM_UNIXTIME(1791460800);
SELECT UNIX_TIMESTAMP();
Time zones: convert at the edges
A timestamp doesn’t have a time zone; the display does. 1791460800 is 12:00 UTC, 13:00 in London (BST), 08:00 in New York (EDT) and 21:00 in Tokyo, all at once.
Best practice:
- Store UTC timestamps (or ISO 8601 strings with
Zor an offset). - Convert to the user’s time zone only when displaying.
- Use IANA zone names (
Europe/London) so daylight saving time is handled; see our time zones guide. - Beware of “naive” date functions that silently use the server’s local time. Python’s
datetime.fromtimestamp(ts)withouttzanddatetime.utcnow()(deprecated) are classic traps.
The year 2038 problem
Many older systems store Unix time in a signed 32-bit integer, whose maximum is 2,147,483,647. One second after 03:14:07 UTC on 19 January 2038, the value overflows to −2,147,483,648, which is interpreted as 13 December 1901.
Who might still be affected:
- Embedded devices and industrial controllers with long lifespans.
- Old 32-bit operating systems and C programs using a 32-bit
time_t. - Database columns defined as 32-bit integers, and MySQL’s
TIMESTAMPtype, whose range ends in January 2038. - File formats and protocols with 32-bit time fields.
Modern 64-bit systems use 64-bit time, which lasts for billions of years. If you’re designing a schema today, use 64-bit integers or native date/time types. Some systems already hit the bug when computing dates more than 12 years ahead, such as long mortgages or certificate expiry dates.
Cron: scheduling with time
Cron runs jobs on a schedule on Unix-like systems, and the same syntax is used by many cloud schedulers and CI pipelines. A standard cron expression has five fields:
┌───────── minute (0–59)
│ ┌─────── hour (0–23)
│ │ ┌───── day of month (1–31)
│ │ │ ┌─── month (1–12)
│ │ │ │ ┌─ day of week (0–6, Sunday = 0; 7 is also Sunday on many systems)
│ │ │ │ │
* * * * * command
| Expression | Meaning |
|---|---|
0 * * * * |
Every hour, on the hour |
*/15 * * * * |
Every 15 minutes |
30 2 * * * |
Every day at 02:30 |
0 9 * * 1-5 |
09:00 Monday to Friday |
0 0 1 * * |
Midnight on the 1st of every month |
0 6 * * 0 |
06:00 every Sunday |
Special characters: * any value, , list (1,15), - range (1-5), / step (*/10).
Cron gotchas
- Time zone: cron uses the server’s time zone unless configured otherwise. Many cloud schedulers default to UTC.
- Daylight saving time: a job at 01:30 may run twice or not at all on clock-change nights. Schedule critical jobs outside 01:00–03:00 local time, or use UTC.
- Day of month and day of week together: in standard cron, if both are restricted, the job runs when either matches.
- Different dialects: Quartz and some platforms add a seconds field or use
?.
Our cron expression generator builds and explains expressions so you can double-check them.
Checklist
- Know whether a timestamp is in seconds or milliseconds.
- Store times in UTC; convert to local time for display.
- Use time-zone-aware functions and IANA zone names.
- Use 64-bit integers or native date types to avoid the 2038 problem.
- Check cron’s time zone and avoid DST transition hours for critical jobs.
Storing timestamps in JSON? See our JSON basics guide.