Milliseconds vs Seconds Mix-up
🚨 The Crime
One of the most insidious bugs in software development: the confusion between Unix timestamps in seconds and JavaScript timestamps in milliseconds. This seemingly simple unit mismatch has caused data corruption, broken integrations, and temporal chaos across countless systems. When your API expects seconds but receives milliseconds (or vice versa), time literally breaks.
💥 Real-World Impact
🐦 Twitter's 2010 Bug
Twitter's API returned timestamps in seconds, but their JavaScript client expected milliseconds. Result: tweets appeared to be from 1970 or the far future.
📊 Analytics Disasters
Google Analytics integrations frequently break when event timestamps are sent in the wrong unit, causing data to appear decades in the past.
💳 Payment Processing
E-commerce platforms have lost millions when payment timestamps were misinterpreted, causing transactions to appear expired or invalid.
🔐 JWT Token Chaos
Authentication systems break when JWT expiration times are calculated with the wrong timestamp unit, causing immediate logouts or eternal sessions.
🤔 The Confusion Explained
Unix Timestamp (Seconds)
Traditional Unix timestamp: seconds since January 1, 1970 UTC
JavaScript Timestamp (Milliseconds)
JavaScript Date.now(): milliseconds since January 1, 1970 UTC
The Disaster
When you mix them up, you get dates that are off by a factor of 1,000:
💻 Code Examples
❌ Problematic: Naive Timestamp Handling
// Dangerous: Assuming timestamp units
function processEvent(timestamp, data) {
// Is this seconds or milliseconds? Who knows!
const eventDate = new Date(timestamp);
if (eventDate.getFullYear() < 2000) {
// Oops, probably got seconds instead of milliseconds
console.log("Event from 1970? That can't be right...");
}
return {
date: eventDate,
data: data
};
}
// API response - what unit is this?
const response = {
created_at: 1692134400, // Seconds? Milliseconds? 🤷♂️
event_data: {...}
};
✅ Safe: Explicit Unit Handling
// Safe: Explicit timestamp handling
class TimestampUtils {
static ensureMilliseconds(timestamp) {
// If it looks like seconds (10 digits), convert to milliseconds
if (timestamp.toString().length === 10) {
return timestamp * 1000;
}
// If it looks like milliseconds (13 digits), use as-is
if (timestamp.toString().length === 13) {
return timestamp;
}
throw new Error(`Invalid timestamp: ${timestamp}`);
}
static ensureSeconds(timestamp) {
// If it looks like milliseconds, convert to seconds
if (timestamp.toString().length === 13) {
return Math.floor(timestamp / 1000);
}
// If it looks like seconds, use as-is
if (timestamp.toString().length === 10) {
return timestamp;
}
throw new Error(`Invalid timestamp: ${timestamp}`);
}
static validateTimestamp(timestamp) {
const date = new Date(this.ensureMilliseconds(timestamp));
const year = date.getFullYear();
// Reasonable range: 1990-2100
if (year < 1990 || year > 2100) {
throw new Error(`Timestamp out of reasonable range: ${date.toISOString()}`);
}
return date;
}
}
// Usage
const eventDate = TimestampUtils.validateTimestamp(apiResponse.timestamp);
✅ API Design: Clear Timestamp Formats
{
"event": {
// Explicit units in field names
"created_at_seconds": 1692134400,
"created_at_ms": 1692134400000,
// Even better: use ISO 8601 strings
"created_at": "2023-08-15T22:00:00.000Z",
// Multiple formats for compatibility
"timestamps": {
"iso": "2023-08-15T22:00:00.000Z",
"unix_seconds": 1692134400,
"unix_milliseconds": 1692134400000
}
}
}
✅ Python: Robust Timestamp Conversion
import time
from datetime import datetime
from typing import Union
class TimestampConverter:
@staticmethod
def to_datetime(timestamp: Union[int, float, str]) -> datetime:
"""Convert various timestamp formats to datetime object"""
if isinstance(timestamp, str):
# Assume ISO 8601 string
return datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
# Numeric timestamp - detect unit by magnitude
if timestamp > 1e12: # Looks like milliseconds
return datetime.fromtimestamp(timestamp / 1000)
elif timestamp > 1e9: # Looks like seconds
return datetime.fromtimestamp(timestamp)
else:
raise ValueError(f"Timestamp {timestamp} doesn't look valid")
@staticmethod
def ensure_seconds(timestamp: Union[int, float]) -> int:
"""Ensure timestamp is in seconds"""
if timestamp > 1e12: # Milliseconds
return int(timestamp / 1000)
elif timestamp > 1e9: # Already seconds
return int(timestamp)
else:
raise ValueError(f"Invalid timestamp: {timestamp}")
@staticmethod
def ensure_milliseconds(timestamp: Union[int, float]) -> int:
"""Ensure timestamp is in milliseconds"""
if timestamp > 1e12: # Already milliseconds
return int(timestamp)
elif timestamp > 1e9: # Seconds
return int(timestamp * 1000)
else:
raise ValueError(f"Invalid timestamp: {timestamp}")
# Usage examples
converter = TimestampConverter()
# These all work regardless of input unit
dt1 = converter.to_datetime(1692134400) # Seconds
dt2 = converter.to_datetime(1692134400000) # Milliseconds
dt3 = converter.to_datetime("2023-08-15T22:00:00Z") # ISO string
🔍 Detection Strategies
1. Sanity Check Ranges
Validate that timestamps fall within reasonable ranges for your application.
if (timestamp < 946684800 || timestamp > 4102444800)
2. Digit Count Validation
Unix seconds: ~10 digits, JavaScript milliseconds: ~13 digits.
const isMilliseconds = timestamp.toString().length === 13
3. Date Reasonableness
Convert to human-readable date and check if it makes sense.
const date = new Date(timestamp * 1000)
4. API Documentation
Always explicitly document timestamp units in your API specs.
// timestamp_ms: Unix timestamp in milliseconds
🛡️ Prevention Strategies
1. Use ISO 8601 Strings
Avoid numeric timestamps entirely. Use standardized date strings.
2. Explicit Unit Naming
Include the unit in field names: timestamp_seconds, timestamp_ms.
3. Validation Functions
Create utility functions that validate and convert timestamps safely.
4. Type Systems
Use TypeScript or other type systems to enforce timestamp types.
📚 Lessons Learned
Units matter: A 1000x difference in timestamp interpretation can break everything.
Be explicit: Always document and validate timestamp units in APIs and databases.
Prefer standards: ISO 8601 strings eliminate unit confusion entirely.
Test edge cases: Include timestamp validation in your test suites.
🔗 Related Time Crimes
💬 Share Your Experience
Have you been bitten by the milliseconds vs seconds bug? Share your story and help others avoid this common pitfall. The more we document these issues, the fewer developers will fall into the same trap.