Skip to content

Search WPDesignVault

Try "image", "json", "schema" or "contrast". Use arrow keys to move through results.

Developer

Unix Timestamps: Seconds, Milliseconds and Time Zones

What a Unix timestamp is, why seconds and milliseconds get mixed up, how to convert correctly in JavaScript, PHP, Python and WordPress, and the time zone traps, all tested.

Comprehensive guide and visual tutorial explaining unix timestamp for WordPress websites.
On this page

A Unix timestamp is the number of seconds since 00:00:00 UTC on 1 January 1970, not counting leap seconds. It is always in UTC; time zones only matter when you convert it to a local date for display. The most common bugs come from mixing seconds and milliseconds. A 10-digit timestamp is in seconds, as used by PHP, Python, MySQL and most APIs. A 13-digit one is in milliseconds, as used by JavaScript's Date. Other common causes are parsing dates without a time zone and storing timestamps in 32-bit fields that overflow in January 2038.

This post explains how timestamps work and how to convert them correctly in JavaScript, PHP, Python and WordPress. It also covers the time zone traps that cause off-by-hours errors. We ran every example in Node.js 22, PHP 8.3, Python 3 and a WordPress 7.1.3 test site, and the outputs shown are from those runs.

What a Unix timestamp is

The timestamp 1791600000 means 1,791,600,000 seconds after the start of 1970 in UTC. That is 10 October 2026 at 02:40:00 UTC. The same moment is 03:40 in London, 08:10 in Kolkata and 22:40 on 9 October in New York. The timestamp does not change; only its local display does.

Table: One timestamp, several local times (computed in Node.js)

Representation Value
Unix timestamp (seconds) 1791600000
Milliseconds 1791600000000
ISO 8601, UTC 2026-10-10T02:40:00Z
London (BST) 10 October 2026, 03:40
Kolkata (IST) 10 October 2026, 08:10
New York (EDT) 9 October 2026, 22:40

Because a timestamp is a single number in UTC, it is ideal for storing and comparing moments in time: sorting events, measuring durations, checking expiry. It is less suited to things that are inherently local, such as "every day at 9:00 in the shop's time zone".

<h2
Step-by-step workflow architecture diagram for implementing unix timestamp on live sites.
Three-phase workflow architecture diagram for generating, deploying, and testing unix timestamp.

Seconds versus milliseconds

Table: Timestamp units by language and system

Environment Current time Unit
JavaScript Date.now() Milliseconds (13 digits today)
PHP time() Seconds (10 digits)
Python time.time() Seconds, with a decimal fraction
MySQL UNIX_TIMESTAMP() Seconds
JSON Web Tokens (exp, iat) N/A Seconds

Mixing them up produces dates that are wildly wrong. In our Node.js run:

new Date(1791600000 * 1000).toISOString()  // "2026-10-10T02:40:00.000Z"  correct
new Date(1791600000).toISOString()         // "1970-01-21T17:40:00.000Z"  seconds passed as ms

A date in January 1970 is the classic sign that seconds were treated as milliseconds. A date tens of thousands of years in the future is the opposite mistake. Convert explicitly at every boundary between a JavaScript front end and a PHP or API back end:

const seconds = Math.floor(Date.now() / 1000);   // JS ms -> s
const date    = new Date(seconds * 1000);        // s -> JS Date

Before you work with timestamps

  • Know the unit of every timestamp you receive: count the digits or read the API documentation.
  • Know which time zone each displayed date should use: the visitor's, the site's or the business's.
  • Store in UTC. Keep timestamps or UTC date-times in the database and convert only for display.
  • Use 64-bit storage for timestamps that may go beyond 2038.
<h2
Recommended best practices checklist and common pitfalls to avoid for unix timestamp.
Implementation checklist comparing recommended best practices against common errors in unix timestamp.

Converting in each language

JavaScript

const ts = 1791600000;
const d = new Date(ts * 1000);
d.toISOString();                                               // UTC
d.toLocaleString('en-GB', { timeZone: 'Europe/London' });      // a named zone
Math.floor(new Date('2026-10-10T02:40:00Z').getTime() / 1000); // back to seconds

PHP

echo gmdate( 'c', 1791600000 );   // 2026-10-10T02:40:00+00:00
$dt = new DateTimeImmutable( '@1791600000' );
echo $dt->setTimezone( new DateTimeZone( 'Asia/Kolkata' ) )->format( 'Y-m-d H:i' );
echo time();                       // current timestamp in seconds

Python

from datetime import datetime, timezone
datetime.fromtimestamp(1791600000, timezone.utc).isoformat()
# '2026-10-10T02:40:00+00:00'
int(datetime(2026, 10, 10, 2, 40, tzinfo=timezone.utc).timestamp())
# 1791600000

Pass a time zone explicitly in Python. Without one, fromtimestamp() converts to the server's local time zone, which may not be what you expect.

For quick checks, the Unix timestamp converter converts in both directions, treats 13-digit values as milliseconds, and shows the result in UTC, your local time and ISO 8601.

The time zone traps

Parsing dates without a zone

JavaScript treats date strings differently depending on their format. We ran this in Node.js with the time zone set to Asia/Kolkata (UTC+5:30):

Table: How JavaScript parsed date strings (Node.js, TZ=Asia/Kolkata)

Input Interpreted as Resulting UTC time
new Date('2026-10-14T10:00:00') Local time 2026-10-14T04:30:00Z
new Date('2026-10-14') UTC midnight 2026-10-14T00:00:00Z
new Date('2026-10-14T10:00:00Z') UTC 2026-10-14T10:00:00Z

A date-time without a zone is local, but a date alone is UTC. The same code gives different timestamps on servers and browsers in different zones. Always include Z or an offset such as +05:30 when exchanging date strings.

Daylight saving time

Local clocks jump; timestamps do not. In our run, 00:30 UTC on 29 March 2026 displayed as 00:30 in London, and 01:30 UTC displayed as 02:30, because British Summer Time began in between. Local 01:30 that morning never existed. When you schedule by local time, use a time zone library or named zones (such as Europe/London), not fixed offsets.

Timestamps in WordPress

WordPress stores post dates twice: post_date in the site's time zone and post_date_gmt in UTC. For timestamps, the functions behave differently:

Table: WordPress time functions (tested on WordPress 7.1.3)

Function Returns Use it for
time() The real Unix timestamp (UTC) Storing and comparing moments
current_time( 'timestamp' ) The timestamp plus the site's UTC offset Avoid in new code; it is not a true Unix timestamp
wp_date( $format, $timestamp ) A formatted date in the site's time zone Displaying dates to visitors
current_time( 'mysql', true ) UTC date-time string Database fields in UTC

With the test site's time zone set to London during British Summer Time, current_time( 'timestamp' ) was exactly 3,600 seconds ahead of time(), and wp_date() printed the local time with "BST". WordPress's own documentation for current_time() explains that the timestamp type returns the timestamp "or a sum of timestamp and timezone offset". Treating that sum as a real timestamp shifts every calculation by the site's offset.

Set the site's time zone in Settings → General using a city name, such as "London", rather than a fixed UTC offset, so daylight saving is applied automatically.

Worked example: a token expiry bug

An illustrative WordPress plugin checks whether a sign-up link has expired. It stores the expiry as current_time( 'timestamp' ) + 3600 and later compares it with time(). On a site set to UTC+5:30, links appear to last 6.5 hours instead of 1, because the stored value already includes the 5.5-hour offset. On a site west of UTC, links expire before they are sent.

The fix is to use time() + HOUR_IN_SECONDS for the stored value and time() for the comparison, and to use wp_date() only when showing the expiry to a person. JSON Web Tokens use the same convention: their exp and iat claims are Unix timestamps in seconds, which the JWT decoder shows as readable dates.

Timestamps in APIs and JSON

JSON has no date type, so APIs send dates either as numbers or as strings. Each choice has its own pitfalls:

Table: Date formats in JSON

Format Example Watch for
Unix seconds 1791600000 Confusion with milliseconds
Unix milliseconds 1791600000000 JavaScript loses precision above 2 to the power of 53 (about 9 quadrillion), but current millisecond timestamps are far below that
ISO 8601 with Z "2026-10-10T02:40:00Z" The safest string form
ISO 8601 without a zone "2026-10-10T02:40:00" Parsed as local time in JavaScript
Local formats "03/04/2026" Ambiguous: 3 April or 4 March? Avoid

When you design an API, pick one format, document it and use it everywhere. When you consume one, check a few real responses rather than trusting the field name. A date that arrives as a string where a number was expected can also make a strict parser fail; our guide to JSON syntax errors covers how to track down malformed responses.

The year 2038 problem

A signed 32-bit integer can hold up to 2,147,483,647. As a timestamp, that is 2038-01-19T03:14:07Z. One second later, a 32-bit counter overflows. In our tests, PHP on a 64-bit system (PHP_INT_SIZE 8) handled 2,147,483,648 normally as 2038-01-19T03:14:08+00:00. Packing the same value into a 32-bit integer in Python raised an error. The risk today is in old 32-bit systems, embedded devices and database columns or file formats that store timestamps in 32 bits. Use 64-bit integers or proper date-time types for anything that may extend past 2038, such as long subscriptions or mortgage schedules.

Verify your conversions

  • Check the digit count of every timestamp entering your code.
  • Convert a known value, such as 1791600000, and confirm you get 2026-10-10T02:40:00Z.
  • Test with a server or browser set to a different time zone; results stored in UTC should not change.
  • Test dates around daylight saving changes.
  • Inspect API responses with a JSON formatter to see exactly what format dates arrive in.

Common mistakes

  • Passing seconds to JavaScript's Date, which expects milliseconds.
  • Exchanging date strings without a time zone.
  • Storing local times instead of UTC.
  • Using fixed offsets such as +01:00 for places with daylight saving.
  • Using current_time( 'timestamp' ) as if it were a true Unix timestamp.
  • Rounding milliseconds inconsistently, so two systems disagree by a second.
  • Storing timestamps in 32-bit fields.

Troubleshooting

Table: Timestamp problems and fixes

Symptom Likely cause Fix
Date shows January 1970 Seconds treated as milliseconds Multiply by 1000 before creating a JavaScript Date
Date far in the future Milliseconds treated as seconds Divide by 1000
Times off by whole hours Missing time zone, or local time stored as UTC Add Z or an offset; store UTC
Off by one hour for part of the year Daylight saving ignored Use named time zones
WordPress expiry checks wrong by the site's offset current_time( 'timestamp' ) compared with time() Use time() for both
Negative or wrapped dates after 2038 32-bit storage Use 64-bit integers or date-time columns

Frequently asked questions

What is a Unix timestamp?

The number of seconds since 00:00:00 UTC on 1 January 1970, not counting leap seconds. It identifies a moment in time independent of time zones.

How do I tell seconds from milliseconds?

Count the digits. Current timestamps in seconds have 10 digits; in milliseconds they have 13.

Are Unix timestamps in UTC?

Yes. A timestamp always counts from a UTC starting point. Time zones apply only when you display it as a local date.

How do I convert a Unix timestamp to a date in JavaScript?

Multiply by 1000 and pass it to new Date(), then use toISOString() for UTC or toLocaleString() with a timeZone option for local time.

How do I get the current timestamp in PHP?

Use time(), which returns seconds. In WordPress, prefer time() over current_time( 'timestamp' ).

What is the year 2038 problem?

Signed 32-bit timestamps can only count to 19 January 2038 at 03:14:07 UTC. Systems that store timestamps in 32 bits will overflow after that.

Why is my date off by a few hours?

Usually a time zone was missing or applied twice: a string parsed as local time, or a local time stored as if it were UTC.

Do Unix timestamps include leap seconds?

No. Unix time treats every day as exactly 86,400 seconds, so leap seconds are not counted.

Should I store dates as timestamps or date strings?

Either works if it is UTC and consistent. Timestamps are compact and easy to compare; ISO 8601 strings with an offset are easier to read.

Which time zone does WordPress use?

The one in Settings → General. It affects displayed dates and post_date, while post_date_gmt and time() stay in UTC.

Next step

Paste a timestamp from your own logs or API into the Unix timestamp converter and confirm the unit and the UTC time. For more developer topics, browse our developer guides.

Unix Timestamp Converter

Convert Unix epoch timestamps to readable dates in UTC and your local time zone, or turn a date…

Related articles

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *