Data formats

How to convert a Unix timestamp to a date

Tell seconds from milliseconds by counting digits, convert a Unix timestamp on a Mac or Linux, get it right in JavaScript, and understand the year 2038 problem.

Sanjeev Maharjan5 min read

A Unix timestamp is the number of seconds since 00:00:00 UTC on 1 January 1970. Count the digits first: a current timestamp in seconds has 10 digits, and one in milliseconds has 13. Then convert it, on a Mac with date -r 1700000000, on Linux with date -d @1700000000, and add -u to see UTC instead of your local time.

The short version: 10 digits means seconds, 13 means milliseconds, so divide by 1000 first. The number is always UTC; only the display is local. Use date -r on macOS and date -d @ on Linux.

What a Unix timestamp is

Unix time counts seconds from a fixed starting point, called the epoch: midnight UTC at the start of 1 January 1970. It ignores time zones and daylight saving entirely, which is exactly why systems like it. Two servers on opposite sides of the world agree on the same number at the same moment. Logs, databases, APIs and tokens all use it; the exp and iat claims in a JWT are Unix timestamps, as the guide on decoding a JWT shows.

The trouble is that a raw number like 1700000000 means nothing to a person. You have to convert it, and there are two easy ways to get the conversion wrong.

Seconds or milliseconds: count the digits

Unix tools, most databases and most APIs use seconds. JavaScript, Java and many browser APIs use milliseconds. For any date in recent decades, the difference is obvious from the length:

DigitsUnitExample
10Seconds1700000000
13Milliseconds1700000000000
16Microseconds1700000000000000

If you treat milliseconds as seconds, you get a date tens of thousands of years in the future. If you treat seconds as milliseconds, you get a moment in January 1970. Either result is a sure sign the unit is wrong. To go from milliseconds to seconds, divide by 1000 and drop the fraction.

UTC vs local time

A timestamp has no time zone. It is one moment, the same everywhere. A time zone only comes in when you display it. The same timestamp shows as one time in London and another in Sydney, and both are correct.

Most bugs here come from mixing the two: storing a local time as if it were UTC, or comparing a UTC time from a server with a local time on a laptop. The safe rule is to store and send timestamps, or UTC dates in ISO 8601 form such as 2023-11-14T22:13:20Z, and convert to local time only at the moment you show it to a person.

Converting in Terminal

The date command differs between macOS and Linux, which trips people up when they copy a command from the web.

# macOS: seconds to a date (local time, then UTC)
date -r 1700000000
date -u -r 1700000000

# macOS: the current timestamp in seconds
date +%s

# macOS: a date to a timestamp
date -j -u -f '%Y-%m-%d %H:%M:%S' '2023-11-14 22:13:20' +%s

# Linux (GNU date): seconds to a date
date -d @1700000000
date -u -d @1700000000

For a 13-digit value, strip the last three digits first, or in a shell write date -r $((1700000000000 / 1000)). You can also format the output, for example date -u -r 1700000000 '+%Y-%m-%dT%H:%M:%SZ' for ISO 8601.

Timestamps in JavaScript

JavaScript works in milliseconds, which is the source of many off-by-1000 bugs when it talks to a backend that works in seconds.

Date.now()                        // milliseconds, 13 digits
Math.floor(Date.now() / 1000)     // seconds, 10 digits

new Date(1700000000 * 1000)       // seconds to a Date
new Date(1700000000 * 1000).toISOString()
// '2023-11-14T22:13:20.000Z'

When an API expects seconds, send Math.floor(Date.now() / 1000). When you receive seconds, multiply by 1000 before passing the value to new Date(). In Python, time.time() returns seconds as a float, and datetime.fromtimestamp(ts, tz=timezone.utc) converts one with an explicit time zone.

The year 2038 problem

Older systems store Unix time in a signed 32-bit integer. The largest value that fits is 2147483647, which is 03:14:07 UTC on 19 January 2038. One second later, the number overflows and wraps round to a negative value, which those systems read as a date in December 1901.

Modern operating systems and languages use 64-bit time, which pushes the limit far beyond any practical concern. The risk lives in old embedded devices, file formats and database columns that still store a 32-bit integer. If you design a schema today, use a 64-bit integer or a proper timestamp type for times.

How DailyUtil does it

DailyUtil's Unix Time tool is free and runs offline on your Mac. If a 10 or 13 digit number is on your clipboard when you open the window, DailyUtil reads the clipboard once, locally, and opens Unix Time for you. It is one of seven free tools in version 0.1, alongside JSON Format, Base64, URL Encode, the JWT Debugger, Hash Generator and UUID. If your timestamp is buried in a JSON response that will not parse, the guide to fixing invalid JSON helps. You can download DailyUtil for macOS 14 or later on Apple Silicon.

Questions people ask

How do I know if a timestamp is in seconds or milliseconds?

Count the digits. A current date in seconds has 10 digits and in milliseconds has 13. If converting gives a date in 1970 or thousands of years ahead, you have the unit the wrong way round.

Is a Unix timestamp in UTC?

Yes. A Unix timestamp counts seconds from the epoch in UTC and has no time zone of its own. Tools show it in your local time by default, so add the UTC flag when you want to see UTC.

Why does date -d not work on my Mac?

macOS ships the BSD version of date, where -d means something else. Use date -r followed by the timestamp instead. The -d @ form belongs to GNU date, which Linux uses.

Will the year 2038 problem affect my Mac?

Not in practice. Modern macOS uses 64-bit time. The risk is in older systems, devices and data formats that store time as a signed 32-bit integer, so check old database columns and file formats.

Share this guide

XLinkedInEmail

Written by Sanjeev Maharjan

Sanjeev Maharjan builds DailyUtil, developer tools for the Mac. Found a mistake in this guide? Write to [email protected].

Keep reading

More guides

Data formats

How to Base64 encode and decode on a Mac

What Base64 is, how it differs from Base64URL, and the Terminal commands that encode and decode it on macOS without surprises.

5 min read

Data formats

How to fix invalid JSON: the common errors

The handful of mistakes behind almost every invalid JSON error, with before and after examples and how to find the position.

5 min read

Tokens and security

How to decode a JWT safely, without a website

Read the header and payload of a JWT offline, make sense of exp, iat and nbf, and know what decoding does not prove.

5 min read

Get DailyUtil

Put the toolbox on your Mac

Free for eight tools, with no time limit and no account. Needs macOS 14 or later on Apple Silicon and Intel.