JSON has no native date type. That single fact causes more bugs than you might expect. When you receive a JSON payload from an API, the timestamp could be an integer, a string, or even an object — and each format requires different handling.
This guide covers every timestamp format you will encounter in JSON, how to parse and convert them, and how to avoid the most common pitfalls when working with date-time data in JSON APIs.
How JSON Handles (or Does Not Handle) Dates
The JSON specification defines exactly six data types: string, number, object, array, boolean, and null. Notice what is missing: there is no date type.
This means every API designer has to make their own choice about how to represent dates in JSON. The three most common approaches are:
| Format | Example | Pros | Cons |
|---|---|---|---|
| Unix timestamp (integer) | 1753401600 |
Compact, sortable, timezone-free | Not human-readable |
| ISO 8601 string | "2026-07-25T00:00:00Z" |
Human-readable, standard | Verbose, parsing required |
| Custom string | "07/25/2026" |
Familiar to end users | Ambiguous, hard to parse |
Most modern REST APIs use either Unix timestamps or ISO 8601 strings. GraphQL APIs tend to favor ISO 8601. Let us look at how to handle each one.
Working with Unix Timestamps in JSON
Receiving Timestamps from an API
When an API returns Unix timestamps as integers, you need to convert them to usable date objects in your code.
// Typical API response
const response = {
"id": 1001,
"name": "Server restart",
"created_at": 1753401600,
"updated_at": 1753488000,
"scheduled_for": 1754092800
};
// Convert to JavaScript Date objects
const event = {
...response,
created_at: new Date(response.created_at * 1000),
updated_at: new Date(response.updated_at * 1000),
scheduled_for: new Date(response.scheduled_for * 1000)
};
console.log(event.created_at.toLocaleString());
// "July 25, 2026, 12:00:00 AM"
The multiplication by 1000 is critical. JavaScript's Date constructor expects milliseconds, but Unix timestamps are in seconds. Forget this step and your dates will be stuck in January 1970.
Sending Timestamps in JSON Requests
When you need to send a timestamp back to an API, convert your date object to a Unix timestamp:
const futureDate = new Date('2026-08-01T00:00:00Z');
const timestamp = Math.floor(futureDate.getTime() / 1000);
const payload = {
event: "Maintenance window",
starts_at: timestamp
};
// Send with fetch
fetch('/api/events', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
Python: Parsing JSON Timestamps
import json
from datetime import datetime, timezone
# JSON response from an API
json_data = '''
{
"id": 1001,
"created_at": 1753401600,
"updated_at": 1753488000
}
'''
data = json.loads(json_data)
# Convert Unix timestamps to datetime objects
data['created_at'] = datetime.fromtimestamp(data['created_at'], tz=timezone.utc)
data['updated_at'] = datetime.fromtimestamp(data['updated_at'], tz=timezone.utc)
print(data['created_at'].isoformat())
# 2026-07-25T00:00:00+00:00
# Convert back to timestamp for API requests
outgoing = {
"event": "Deploy",
"scheduled_at": int(datetime(2026, 8, 1, tzinfo=timezone.utc).timestamp())
}
print(json.dumps(outgoing))
# {"event": "Deploy", "scheduled_at": 1754092800}
Working with ISO 8601 Strings in JSON
ISO 8601 is the international standard for date-time representation. It looks like this: 2026-07-25T00:00:00Z.
JavaScript: Parsing ISO Strings
const jsonStr = '{"event": "Deploy", "time": "2026-07-25T00:00:00Z"}';
const data = JSON.parse(jsonStr);
// JavaScript natively parses ISO 8601 strings
const date = new Date(data.time);
console.log(date.toISOString()); // "2026-07-25T00:00:00.000Z"
console.log(date.getTime()); // 1753401600000 (milliseconds)
// Convert to Unix timestamp (seconds)
const unixTs = Math.floor(date.getTime() / 1000);
console.log(unixTs); // 1753401600
Python: Parsing ISO Strings
import json
from datetime import datetime, timezone
json_str = '{"event": "Deploy", "time": "2026-07-25T00:00:00Z"}'
data = json.loads(json_str)
# Parse ISO 8601 string (Python 3.7+)
dt = datetime.fromisoformat(data['time'].replace('Z', '+00:00'))
print(dt) # 2026-07-25 00:00:00+00:00
# Convert to Unix timestamp
ts = int(dt.timestamp())
print(ts) # 1753401600
Handling Mixed Timestamp Formats
Real-world APIs are messy. Sometimes the same API returns different timestamp formats in different endpoints, or even within the same response. Here is how to handle that gracefully.
JavaScript: Auto-Detect Format
function parseTimestamp(value) {
// If it is a number, assume Unix timestamp in seconds
if (typeof value === 'number') {
// Heuristic: 10 digits = seconds, 13 digits = milliseconds
if (value > 1e12) {
return new Date(value); // already milliseconds
}
return new Date(value * 1000); // convert seconds to ms
}
// If it is a string, try ISO 8601 first
if (typeof value === 'string') {
const date = new Date(value);
if (!isNaN(date.getTime())) {
return date;
}
}
throw new Error(`Cannot parse timestamp: ${value}`);
}
// Works with all common formats
console.log(parseTimestamp(1753401600)); // Unix seconds
console.log(parseTimestamp(1753401600000)); // Unix milliseconds
console.log(parseTimestamp("2026-07-25T00:00:00Z")); // ISO 8601
Python: Auto-Detect Format
from datetime import datetime, timezone
def parse_timestamp(value):
if isinstance(value, (int, float)):
# Heuristic: > 1e12 means milliseconds
if value > 1e12:
return datetime.fromtimestamp(value / 1000, tz=timezone.utc)
return datetime.fromtimestamp(value, tz=timezone.utc)
if isinstance(value, str):
# Try ISO 8601
try:
return datetime.fromisoformat(value.replace('Z', '+00:00'))
except ValueError:
pass
raise ValueError(f"Cannot parse timestamp: {value}")
# Works with all common formats
print(parse_timestamp(1753401600)) # Unix seconds
print(parse_timestamp(1753401600000)) # Unix milliseconds
print(parse_timestamp("2026-07-25T00:00:00Z")) # ISO 8601
Timestamps in JSON Schema and Validation
When you define a JSON Schema for your API, you can specify the expected timestamp format:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"created_at": {
"type": "integer",
"description": "Unix timestamp in seconds",
"minimum": 0,
"maximum": 2147483647
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 date-time string"
}
},
"required": ["created_at"]
}
The "format": "date-time" constraint tells validators to expect an ISO 8601 string. For Unix timestamps, use "type": "integer" with reasonable min/max bounds.
Converting JSON Timestamps for Display
Once you have parsed a timestamp from JSON, you usually need to format it for display. Here are common patterns.
JavaScript: Formatting for Users
function formatTimestamp(ts, locale = 'en-US') {
const date = new Date(ts * 1000);
return {
// Full date and time
long: date.toLocaleString(locale, {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
}),
// Short date only
short: date.toLocaleDateString(locale),
// Relative time ("2 hours ago")
relative: getRelativeTime(date)
};
}
function getRelativeTime(date) {
const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
const intervals = [
{ label: 'year', seconds: 31536000 },
{ label: 'month', seconds: 2592000 },
{ label: 'week', seconds: 604800 },
{ label: 'day', seconds: 86400 },
{ label: 'hour', seconds: 3600 },
{ label: 'minute', seconds: 60 }
];
for (const interval of intervals) {
const count = Math.floor(seconds / interval.seconds);
if (count >= 1) {
return `${count} ${interval.label}${count > 1 ? 's' : ''} ago`;
}
}
return 'just now';
}
// Usage
const result = formatTimestamp(1753401600);
console.log(result.long); // "July 25, 2026, 12:00 AM"
console.log(result.short); // "7/25/2026"
console.log(result.relative); // "X days ago"
FAQ
What is the best timestamp format for JSON APIs?
There is no single "best" format. Unix timestamps (integers) are compact and easy to compare, making them ideal for internal APIs and database storage. ISO 8601 strings are human-readable and self-documenting, making them better for public APIs and developer-facing documentation. Choose based on your audience.
How do I handle timezone information in JSON timestamps?
Unix timestamps are inherently timezone-free (they always represent UTC). ISO 8601 strings can include timezone offsets (+05:30) or use Z for UTC. The safest approach: store and transmit everything in UTC, convert to local time only in the UI layer.
Why does my JSON timestamp show the wrong date?
The most common cause is the seconds vs milliseconds confusion. If your timestamp has 10 digits, it is in seconds. If it has 13 digits, it is in milliseconds. Passing a seconds value to a function expecting milliseconds (or vice versa) will produce wildly incorrect dates.
Can I store dates directly in JSON?
No. JSON has no date type. You must use either a number (Unix timestamp) or a string (ISO 8601 or custom format). This is by design — the JSON specification intentionally keeps the type system minimal.
How do I validate timestamp formats in JSON?
Use JSON Schema validation. For ISO 8601 strings, use "format": "date-time". For Unix timestamps, use "type": "integer" with minimum and maximum constraints. Libraries like Ajv (JavaScript) and jsonschema (Python) can enforce these rules automatically.
Conclusion
JSON has no native date type, which means every developer must handle timestamp conversion manually. The two dominant formats — Unix timestamps (integers) and ISO 8601 strings — each have their strengths and trade-offs.
Key takeaways:
- Always check whether a JSON timestamp is in seconds (10 digits) or milliseconds (13 digits) before converting
- ISO 8601 strings are human-readable but require parsing; Unix timestamps are compact but opaque
- Store and transmit timestamps in UTC; convert to local time only at the display layer
- Use auto-detection functions to handle APIs that mix timestamp formats
When you need to quickly inspect or convert timestamp values in JSON data, the FastUnix JSON Formatter can help you validate and beautify JSON payloads, while the FastUnix Timestamp Converter provides instant conversion between Unix timestamps and human-readable dates. For encoding timestamps in URL parameters, the URL Encoder handles special characters correctly.