You inspect an API response and find this:
{
"userId": 1042,
"createdAt": 1700000000,
"lastLogin": 1700000000000
}
Both fields represent Unix timestamps.
Both contain numbers.
But one is measured in seconds, and the other in milliseconds.
If you handle them incorrectly, your application might display a date in 1970, create a completely unrealistic future date, or incorrectly decide that an authentication token has expired.
These bugs are especially frustrating because the timestamps look valid.
Let's investigate how they happen, how to fix them in JavaScript, and how to debug timestamps more quickly.
1. What exactly is a Unix timestamp?
A Unix timestamp represents elapsed time since the Unix epoch:
January 1, 1970, at 00:00:00 UTC.
It represents an instant in time, independent of how that instant is displayed in different time zones.
For example:
1700000000
This timestamp, measured in seconds, represents:
2023-11-14 22:13:20 UTC
The same instant in India is:
2023-11-15 03:43:20 IST
The underlying instant hasn't changed.
Only its local representation has changed.
That distinction is essential when working with APIs, logs, authentication tokens, databases, and international applications.
2. The most common mistake: seconds vs milliseconds
Unix timestamps are commonly represented in two units:
- Seconds
- Milliseconds
JavaScript's Date constructor expects a numeric timestamp in milliseconds.
Many backend APIs, including systems that use Unix seconds, provide timestamps in seconds.
This difference creates one of the most common timestamp bugs.
Incorrect example
const timestamp = 1700000000;
const date = new Date(timestamp);
console.log(date.toISOString());
Output:
1970-01-20T16:13:20.000Z
That is probably not the date you expected.
The problem is that JavaScript interpreted the value as milliseconds.
Correct example
const timestampInSeconds = 1700000000;
const date = new Date(
timestampInSeconds * 1000
);
console.log(date.toISOString());
Output:
2023-11-14T22:13:20.000Z
Multiplying by 1,000 converts seconds into milliseconds.
The reverse mistake
What happens if you multiply an existing millisecond timestamp by 1,000?
const timestampInMilliseconds = 1700000000000;
const incorrectDate = new Date(
timestampInMilliseconds * 1000
);
console.log(Number.isNaN(incorrectDate.getTime()));
Output:
true
The resulting numeric value exceeds JavaScript's supported Date range.
This is why blindly multiplying timestamps is dangerous.
The correct solution is to know the timestamp's unit before converting it.
3. Why guessing from the number of digits can fail
You might have seen code like this:
function convertTimestamp(value) {
const milliseconds =
String(value).length === 10
? value * 1000
: value;
return new Date(milliseconds);
}
This might work for common modern timestamps.
But it is not a reliable universal solution.
Why?
Because timestamp length depends on the timestamp's value and unit.
For example:
- Negative timestamps represent dates before the Unix epoch.
- Earlier positive timestamps may have fewer digits.
- Larger timestamps may have more digits.
- Some systems use microseconds or nanoseconds.
A reliable API should document which unit it returns.
When possible, make the unit explicit in your code.
function fromUnixSeconds(seconds) {
if (!Number.isFinite(seconds)) {
throw new TypeError(
"Expected a finite number of seconds"
);
}
const date = new Date(seconds * 1000);
if (Number.isNaN(date.getTime())) {
throw new RangeError("Timestamp is outside Date range");
}
return date;
}
function fromUnixMilliseconds(milliseconds) {
if (!Number.isFinite(milliseconds)) {
throw new TypeError(
"Expected a finite number of milliseconds"
);
}
const date = new Date(milliseconds);
if (Number.isNaN(date.getTime())) {
throw new RangeError("Timestamp is outside Date range");
}
return date;
}
console.log(
fromUnixSeconds(1700000000).toISOString()
);
console.log(
fromUnixMilliseconds(1700000000000).toISOString()
);
Both return:
2023-11-14T22:13:20.000Z
These functions make the expected unit clear.
For production applications, also validate whether the input is an integer and whether it matches your API's contract.
4. A real-world bug: Authentication token expiration
Suppose your backend returns an expiration timestamp:
{
"accessToken": "example-token",
"expiresAt": 1700003600
}
Assume the API contract specifies that expiresAt is measured in Unix seconds.
You want to determine whether the token has expired.
Incorrect comparison
const expiresAt = 1700003600;
const expired = Date.now() >= expiresAt;
console.log(expired);
The problem?
Date.now() returns milliseconds.
expiresAt is in seconds.
You're comparing two different units.
The result will be incorrect for many real-world scenarios.
Correct comparison
const expiresAtSeconds = 1700003600;
const expiresAtMilliseconds =
expiresAtSeconds * 1000;
const isExpired =
Date.now() >= expiresAtMilliseconds;
console.log(isExpired);
Now both values use milliseconds.
For real authentication systems, expiration checks may also incorporate clock skew or a safety margin.
And remember: decoding a JWT's expiration claim does not validate its signature or establish that the token is trustworthy.
Only trusted, properly verified token data should drive security decisions.
5. Unix timestamps and time zones
Here's another common misunderstanding:
A Unix timestamp does not have a time zone.
It identifies a particular instant.
Time zones determine how that instant is displayed to people.
Consider:
const timestamp = 1700000000;
const date = new Date(timestamp * 1000);
console.log(date.toISOString());
Output:
2023-11-14T22:13:20.000Z
Now display the same instant in India:
const indiaTime = new Intl.DateTimeFormat(
"en-IN",
{
timeZone: "Asia/Kolkata",
dateStyle: "medium",
timeStyle: "medium",
hourCycle: "h23"
}
).format(date);
console.log(indiaTime);
The exact presentation depends on locale formatting rules, but the time corresponds to:
15 Nov 2023, 03:43:20 IST
Now consider New York:
const newYorkTime = new Intl.DateTimeFormat(
"en-US",
{
timeZone: "America/New_York",
dateStyle: "medium",
timeStyle: "medium"
}
).format(date);
console.log(newYorkTime);
The time corresponds to:
November 14, 2023, 5:13:20 PM EST
One instant.
Different local times.
Neither representation changes the timestamp.
Practical rule
Store and transmit unambiguous instants.
Convert them into an appropriate time zone when displaying information to users.
And avoid assuming that every time zone has a fixed UTC offset all year.
6. Daylight saving time makes things more complicated
Consider this local time:
2026-11-01 01:30
America/New_York
On this date, New York transitions from daylight saving time to standard time.
The local clock repeats the hour between 1:00 AM and 2:00 AM.
That means 1:30 AM occurs twice.
The two possible instants are:
2026-11-01T05:30:00Z
2026-11-01T06:30:00Z
They have different UTC offsets:
01:30 EDT (UTC-04:00)
01:30 EST (UTC-05:00)
Simply specifying "1:30 AM in New York" is not enough to identify a unique instant.
This matters when building:
- Meeting schedulers
- Automated jobs
- Booking systems
- Financial transaction logs
- Monitoring applications
A robust system must define what happens when a local time is repeated or skipped.
For instance, on the spring daylight-saving transition, certain local times do not exist at all.
Time-zone conversion should preserve the instant, while local-time interpretation must account for ambiguity.
7. Debugging timestamps without writing temporary scripts
Sometimes you're not building date-handling logic.
You simply need to investigate a production log, inspect an API response, or check a timestamp from a database.
Writing a temporary JavaScript script every time can become repetitive.
This is one reason I built the Unix Timestamp Converter as part of ToolZenHub.
You can use it here:
https://toolzenhub.in/tools/unix-timestamp-converter/
It runs directly in your browser.
Let's walk through the earlier example.
Step 1: Enter the timestamp
Paste:
1700000000
Step 2: Confirm the unit
Select Seconds.
The tool also provides an automatic unit-detection option, but explicitly selecting the unit is useful when you already know the API contract.
Step 3: Choose your time zone
Select the time zone in which you want to inspect the timestamp.
For example:
Asia/Kolkata
The converted time corresponds to:
15 November 2023
03:43:20 IST
Step 4: Compare the same instant across zones
The converter supports displaying the same timestamp in multiple time zones.
This can be useful when investigating an event involving users or servers in different countries.
Step 5: Convert a date back into a timestamp
You can also enter a date and time with its time zone and convert it into a Unix timestamp.
This is particularly useful when preparing test data or checking scheduled events.
The tool explains ambiguous or nonexistent daylight-saving times rather than silently choosing an interpretation.
8. Debugging multiple timestamps from logs
Now imagine you receive these timestamps:
1700000000
1700000300
1700000600
1700000900
You want to understand the event sequence.
You could write a script:
const timestamps = [
1700000000,
1700000300,
1700000600,
1700000900
];
const events = timestamps.map((timestamp) => ({
timestamp,
utc: new Date(timestamp * 1000).toISOString()
}));
console.table(events);
This works well for reusable automation.
But sometimes you only need a quick investigation.
ToolZenHub's Unix Timestamp Converter also supports batch conversion.
You can paste multiple timestamp values or compatible log lines.
The tool supports up to 200 values in one batch and uses the selected time zone for the results.
This helps avoid repeatedly converting individual timestamps during a debugging session.
For very large log files, a dedicated script or approved log-analysis system is more appropriate.
9. What about microseconds and nanoseconds?
Not every system uses seconds or milliseconds.
Some databases and telemetry systems represent timestamps with microsecond or nanosecond precision.
For the same example instant:
| Unit | Timestamp |
|---|---|
| Seconds | 1700000000 |
| Milliseconds | 1700000000000 |
| Microseconds | 1700000000000000 |
| Nanoseconds | 1700000000000000000 |
A critical problem arises when working with large integers in JavaScript.
JavaScript's standard Number type cannot represent every integer above:
9007199254740991
This is Number.MAX_SAFE_INTEGER.
Modern nanosecond timestamps commonly exceed that limit.
For example:
const timestamp = 1700000000000000000;
console.log(Number.isSafeInteger(timestamp));
Output:
false
This means you should not assume that converting a nanosecond timestamp to Number preserves its exact integer value.
Use BigInt when exact integer arithmetic is required
const nanoseconds = 1700000000000000000n;
const milliseconds =
nanoseconds / 1000000n;
console.log(milliseconds.toString());
Output:
1700000000000
This example produces exact millisecond precision because the original timestamp is an exact multiple of one million nanoseconds.
For timestamps with sub-millisecond components, integer division drops the remainder unless you preserve it separately.
Also note that native JavaScript Date objects only represent time at millisecond precision.
If your application needs exact microsecond or nanosecond values, preserve those values in an appropriate integer or timestamp representation rather than relying solely on Date.
The ToolZenHub converter supports seconds, milliseconds, microseconds, and nanoseconds, including exact handling of large timestamp values.
10. A safer approach to API timestamp design
A major source of timestamp bugs is unclear API documentation.
Consider this response:
{
"createdAt": 1700000000
}
The client has to guess the unit.
A clearer contract could use an explicitly named field:
{
"createdAtUnixSeconds": 1700000000
}
Another option is an unambiguous ISO 8601 timestamp:
{
"createdAt": "2023-11-14T22:13:20Z"
}
Both approaches can work.
The important part is consistency.
For an API contract, document:
- Whether the timestamp represents an instant or a local date and time.
- The unit used for numeric timestamps.
- The expected precision.
- The accepted date range.
- How time zones are handled.
- Whether missing or invalid timestamps are allowed.
This makes client implementations and automated tests more predictable.
11. A practical timestamp-debugging checklist
When you encounter a suspicious timestamp, check the following:
1. What is the original value?
Avoid converting the value before recording what the API actually returned.
2. What unit does the API use?
Seconds, milliseconds, microseconds, or nanoseconds?
3. Is the timestamp within the expected range?
An application created in 2026 probably shouldn't have an ordinary creation timestamp in 1970.
4. Are you mixing Date.now() with Unix seconds?
Remember that Date.now() uses milliseconds.
5. Are you parsing a date with an explicit UTC offset?
For example:
2026-10-28T10:00:00+05:30
This identifies an instant.
A local date-time string without an offset may require a separate time-zone interpretation.
6. Does daylight saving apply?
Some local times are ambiguous or nonexistent.
7. Are you losing precision?
Be especially careful when processing microsecond and nanosecond timestamps.
8. Are the expected and actual values using the same unit?
Never compare seconds directly with milliseconds.
Final thoughts
Unix timestamps are simple in principle.
But timestamp bugs often arise from hidden assumptions:
- Assuming a number is measured in milliseconds.
- Guessing units from digit count.
- Mixing local time with UTC.
- Ignoring daylight-saving transitions.
- Losing precision when handling large integers.
- Comparing values expressed in different units.
A little clarity around units and time zones prevents many of these problems.
For reusable application logic, write explicit conversion functions and automated tests.
For quick investigation, a timestamp converter can make debugging faster.
If you need to inspect API timestamps, compare time zones, or convert several log entries, you can try the ToolZenHub utility I maintain:
https://toolzenhub.in/tools/unix-timestamp-converter/
The goal isn't to replace understanding with another tool.
It's to remove repetitive conversion work so you can focus on the actual issue.
References
Disclosure: I maintain ToolZenHub, the tool website referenced in this tutorial. This article was created with AI assistance and should be reviewed for technical accuracy before publication.
Top comments (0)