Time in distributed systems is notoriously deceptive. A system spanning user clients in Tokyo, edge workers in Frankfurt, message queues in AWS us-east-1, and analytical databases in Snowflake will fail silently if timestamp representations are ambiguous.
Common symptoms of improper timestamp handling include:
- Financial transactions booked on the wrong calendar day.
- Auth tokens expiring before they are issued due to clock skew.
- Microsecond timestamps parsed as milliseconds, producing dates in the year 53,000.
- Database queries returning inaccurate time ranges because
TIMESTAMP(without timezone) was used instead ofTIMESTAMPTZ.
This guide outlines the mathematical foundations and production rules for handling timestamps, ISO 8601 / RFC 3339 strings, and timezones with zero discrepancies.
1. The Golden Rule of Distributed Time
+-------------------------------------------------------------------------------+
| Store and Transmit in UTC. Format in Local Time ONLY at the Presentation Layer.|
+-------------------------------------------------------------------------------+
[Browser (Client - JST)] --> [ISO 8601 UTC String: "2026-09-04T12:00:00.000Z"]
|
v
[API Gateway / Microservice] --> [Unix Epoch Milliseconds / TIMESTAMPTZ (UTC)]
|
v
[PostgreSQL / MySQL / Kafka] --> [Raw UTC / BigInt]
|
v
[Rendering to User in London] --> [Intl.DateTimeFormat(locale, 'Europe/London')]
- Storage: Always store timestamps as UTC (either as standard integer epoch timestamps or
TIMESTAMP WITH TIME ZONE). - Network Transport: Transmit timestamps over JSON REST or GraphQL APIs as RFC 3339 / ISO 8601 strings with explicit
Zsuffix or integer epoch milliseconds. - Display: Only convert to user-local timezone (e.g.,
America/New_YorkorAsia/Tokyo) in the frontend UI or email template rendering step.
2. Unix Epoch Timestamp Precision: Seconds vs Milliseconds vs Microseconds
A Unix epoch timestamp represents the number of elapsed time units since January 1, 1970 00:00:00 UTC (excluding leap seconds).
| Unit | Decimal Length | Example Representation | Common Systems |
|---|---|---|---|
| Seconds ($s$) | 10 digits | 1788523200 |
POSIX time(), Python time.time() (int), Redis TTL, JWT exp / iat |
| Milliseconds ($ms$) | 13 digits | 1788523200000 |
JavaScript Date.now(), Java System.currentTimeMillis() |
| Microseconds ($\mu s$) | 16 digits | 1788523200000000 |
Python datetime.now().timestamp(), PostgreSQL timestamp |
| Nanoseconds ($ns$) | 19 digits | 1788523200000000000 |
Go time.Now().UnixNano(), Rust SystemTime, Linux kernel |
Quick Heuristic for Auto-Detecting Precision
export function normalizeTimestampToMs(val: number): number {
if (val < 1e11) {
// 10 digits -> Seconds (e.g. 1788523200)
return val * 1000;
}
if (val < 1e14) {
// 13 digits -> Milliseconds (e.g. 1788523200000)
return val;
}
if (val < 1e17) {
// 16 digits -> Microseconds (e.g. 1788523200000000)
return Math.floor(val / 1000);
}
// 19 digits -> Nanoseconds
return Math.floor(val / 1_000_000);
}
3. ISO 8601 vs RFC 3339: What Every API Author Needs to Know
While ISO 8601 is an expansive international standard with dozens of optional variants, RFC 3339 is the strict profile designed specifically for the Internet and JSON APIs.
2026-09-04T14:30:00.123Z
^^^^-^^-^^ ^^-^^-^^ ^^^ ^
| | | | | | | +-- 'Z' = UTC (Zulu time, 00:00 offset)
| | | | | | +----- Milliseconds (optional, 1-3 digits)
| | | +--+--+--------- Hours:Minutes:Seconds (24-hour format)
| | |
+---+--+------------------- Year-Month-Day (Gregorian calendar)
The Difference between Z and +00:00
2026-09-04T14:30:00Zand2026-09-04T14:30:00+00:00are mathematically identical.- However,
Zis shorter and universally parsed across all language runtimes without regex edge cases.
Avoid Non-Standard Offsets Without Delimiters
- Standard:
+05:30or-08:00 - Non-standard (often fails):
+0530or-08
4. Database Column Types: PostgreSQL vs MySQL
PostgreSQL
- Use
TIMESTAMPTZ(timestamp with time zone): PostgreSQL converts the incoming string to UTC internally and stores it as an 8-byte integer. When querying, it converts from UTC to the client's connection timezone. - Do NOT use
TIMESTAMP(without time zone): It discards all timezone offsets and assumes whatever timezone the server clock happens to have.
-- Correct schema design in PostgreSQL
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
action VARCHAR(64) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
MySQL
TIMESTAMP: Stores UTC internally as a 4-byte integer (limited to range 1970–2038). Converts to connection timezone on read.DATETIME(6): Stores literal date and time up to microsecond precision without converting. When usingDATETIME, ensure your application explicitly persists UTC values.
5. Modern JavaScript / TypeScript: Temporal API vs Intl
Modern web applications should use the native Intl.DateTimeFormat for reliable timezone conversions without importing bulky libraries:
// Safe formatting across arbitrary IANA timezone names
export function formatToUserTimezone(
utcTimestampMs: number,
timeZone: string = 'America/New_York',
locale: string = 'en-US'
): string {
const formatter = new Intl.DateTimeFormat(locale, {
timeZone,
year: 'numeric',
month: 'short',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
timeZoneName: 'short',
});
return formatter.format(new Date(utcTimestampMs));
}
// Example Output:
// formatToUserTimezone(Date.now(), 'Asia/Tokyo') => "Sep 04, 2026, 11:30:00 PM GMT+9"
// formatToUserTimezone(Date.now(), 'Europe/London') => "Sep 04, 2026, 03:30:00 PM BST"
6. Summary Checklist for Zero Discrepancy
- Always use UTC for server clocks, container environments (
TZ=UTC), database servers, and log aggregators. - Use RFC 3339 strings (
YYYY-MM-DDTHH:mm:ss.sssZ) for public API interfaces. - Use 64-bit integer epoch milliseconds for internal RPCs or high-throughput message streaming.
- Never perform manual arithmetic for timezones (e.g.
timestamp + (5.5 * 3600)). Timezones have shifting Daylight Saving Time rules that change dynamically. Use standard IANA timezone databases (America/New_York,Europe/Berlin,Asia/Kolkata).
Use the Timestamp Converter to inspect epoch timestamps across precisions and the Timezone Converter to calculate meeting schedules and DST offsets.