EPOCH(1)toolbelt manualEPOCH(1)

epoch

Convert Unix timestamps and dates both ways.

Synopsis

epoch [options] [timestamp | date]

Description

A Unix timestamp counts the seconds since 1970-01-01 00:00:00 UTC. Logs, databases, JWTs, Kubernetes objects and most APIs store times this way, and none of us can read 1790000000 at a glance.

Give epoch a number and it prints that moment in your local time, in UTC, and how long ago it was:

local  Mon 2026-09-21 19:43:20 IST
utc    Mon 2026-09-21 14:13:20 UTC
ago    8 days

Give it a date and it prints the timestamp:

epoch "2026-09-29 14:30"
1790672400

Give it nothing and it prints the timestamp of this moment.

How it tells a number from a date

Input that is only digits, with an optional minus sign and an optional fraction, is a timestamp. @1790000000, the form date -d uses, is a timestamp too. Anything else is a date.

Many systems count in milliseconds or smaller units, and the number of digits gives it away. A timestamp for a date between 2001 and 2286 has 10 digits in seconds, 13 in milliseconds, 16 in microseconds and 19 in nanoseconds. epoch reads the number by its length:

DigitsRead asSeen in
up to 11secondsUnix tools, JWT exp and iat, most APIs
12 to 14millisecondsJavaScript Date.now(), Java, Elasticsearch, Kafka
15 to 17microsecondsPostgreSQL, Python time.time_ns() // 1000
18 and 19nanosecondsGo, Prometheus, Loki, containerd logs

When it reads the number as anything but seconds, it says so on stderr, epoch: read as milliseconds, and shows the first three digits of the fraction.

A fraction, as in 1790000000.5, is seconds with a decimal part, which Python's time.time() and many JSON logs print.

The "ago" line

The last line counts from now to the timestamp in the two largest units that apply: years, days, hours, minutes and seconds. A time in the future says in instead of ago. A year counts as 365 days, so over many years the count drifts by a day for each leap year.

Dates it reads

epoch hands a date to date -d, so it reads everything GNU date reads:

A date without a zone is local time. -u reads it as UTC. A date with a zone, such as Z or +05:30, ignores -u, because it already says which zone it is in.

Words after epoch join with spaces, so epoch 2026-09-29 14:30 works without quotes.

Options

OptionWhat it does
-u, --utcRead a date without a zone as UTC, not local time.
--msPrint the timestamp in milliseconds, for a date or for now.
-q, --quietHide the "read as" line.
-v, --verbosePrint how it read the input and the date command it runs. For a date, also print the date back in full, so you can check it read what you meant.
-h, --helpShow the help.

Time zones

The local line uses your time zone, from TZ or the system setting. Set TZ for one command to see a timestamp in another place:

TZ=America/New_York epoch 1790000000
local  Mon 2026-09-21 10:13:20 EDT
utc    Mon 2026-09-21 14:13:20 UTC
ago    8 days

timedatectl list-timezones lists the names.

Pass-through

None. It calls date with fixed options.

Needs

date from coreutils, or BusyBox date as on Alpine. BusyBox reads 2026-09-29 14:30 but not ISO 8601, so when it refuses a date such as 2026-09-29T09:00:00.25Z, epoch splits off the T, the zone and the fraction and gives it the plain 2026-09-29 09:00:00. -v shows that second date call. The HTTP form and words such as yesterday still need GNU date.

Examples

A timestamp from a log

epoch 1790000000
local  Mon 2026-09-21 19:43:20 IST
utc    Mon 2026-09-21 14:13:20 UTC
ago    8 days

Milliseconds

epoch 1790000000123
epoch: read as milliseconds
local  Mon 2026-09-21 19:43:20.123 IST
utc    Mon 2026-09-21 14:13:20.123 UTC
ago    8 days

When a token expires

epoch 1800000000
local  Fri 2027-01-15 13:30:00 IST
utc    Fri 2027-01-15 08:00:00 UTC
in     107 days, 16 hours

A date to a timestamp

epoch "2026-09-29 14:30"
1790672400

The same moment, typed in UTC

epoch -u 2026-09-29 09:00
1790672400

Checking what it read

epoch -v 2026-09-29T09:00:00Z
+ date -d 2026-09-29T09:00:00Z +%s
epoch: Tue 2026-09-29 14:30:00 IST
1790672400

Milliseconds for an API

epoch --ms "2026-09-29 14:30:00.250"
1790672400250

Something it cannot read

epoch next-ish
epoch: cannot read next-ish as a timestamp or a date
Try 'epoch --help' for the options.

Troubleshooting

epoch: cannot read next-ish as a timestamp or a date
date -d did not understand the text. Write the date as 2026-09-29 14:30, or check it with date -d 'text'.
The date is off by hours
A date without a zone is local time. For a UTC time from a log, add -u, or write the zone, as in 2026-09-29T09:00:00Z.
A timestamp shows a date in 1970 or far in the future
The number is in a different unit than its length suggests, such as a 13-digit value in seconds, or a value someone cut short. Divide or multiply by 1000 and try again.
A year in the thousands, such as 5138
An 11-digit number reads as seconds, and 99999999999 seconds is more than 3000 years. The number is probably milliseconds with its last digits cut off.

Exit status

CodeMeaning
0It worked.
1It failed, such as a timestamp too large for date to show.
2The input is neither a timestamp nor a date.
3date is missing.

See also

jwtpeek, date(1)