Unix Timestamps: UTC, CST and Daylight Saving Time
Handling timezones in internationalized apps can easily lead to bugs: Does 'CST' mean China Standard Time (UTC+8) or Central Standard Time (UTC-6)? How do we account for the missing or extra hour during Daylight Saving Time (DST) transitions? This article explains timezone physics and IANA standards.
1. Problem: timezone abbreviation ambiguities and DST clock shift errors
Distributed systems suffer from two main timezone bugs: First, passing ambiguous 3-letter abbreviations like CST causes US and Chinese teams to interpret times as UTC-6 and UTC+8 respectively (a 14-hour discrepancy); second, adding +24h during Daylight Saving Time (DST) transitions in March/November causes 1-hour calculation errors.
2. Minimal reproduction: CST ambiguities and DST arithmetic failures
This example demonstrates the ambiguity of 'CST' and the failure of hardcoded millisecond additions across DST transitions:
/* Pitfall 1: "CST" abbreviation has at least 4 distinct meanings! */
// - China Standard Time: UTC+8
// - Central Standard Time (USA): UTC-6
// - Cuba Standard Time: UTC-5
// - Australia Central Standard Time: UTC+9:30
// Passing "CST" leaves the receiver unable to determine the physical instant!
/* Pitfall 2: Adding 24 hours (86,400,000 ms) on DST transition day */
// On DST spring-forward days (e.g., 2024-03-10), a day has only 23 hours!3. Root cause: decoupling Instants from Zone Views
1. Instant: a globally unique point in physical time, identified by Unix timestamps or UTC ISO strings (with Z), independent of geographic location. 2. Zone View: converts an Instant into local year, month, day, hour, minute, second values per geographic rules. 3. IANA tz database: timezone rules change due to political or historical factors. Always use IANA names (e.g., Asia/Shanghai or America/Chicago) rather than static offsets like UTC+8.
4. Recommendation: store UTC on the backend, format dynamically with IANA on the frontend
1. Unified storage: store and transmit UTC millisecond timestamps or ISO 8601 UTC strings (2026-07-28T12:00:00Z). 2. Localized rendering: use native Intl.DateTimeFormat with timeZone: 'Asia/Shanghai'. 3. Avoid hardcoded offsets: delegate DST transitions and calendar calculations to timezone libraries.
5. Complete code: IANA timezone formatting with native Intl.DateTimeFormat
This TypeScript snippet demonstrates using modern JavaScript native Intl APIs to safely format absolute timestamps into localized representations for any IANA timezone.
function formatZonedDateTime(
timestamp: number | Date,
timeZone: string,
locale = "zh-CN"
): string {
const date = typeof timestamp === "number" ? new Date(timestamp) : timestamp;
if (isNaN(date.getTime())) {
throw new RangeError("Invalid date input");
}
const formatter = new Intl.DateTimeFormat(locale, {
timeZone: timeZone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
});
return formatter.format(date);
}
const now = 1700000000000;
console.log("Beijing Time:", formatZonedDateTime(now, "Asia/Shanghai"));
console.log("Chicago Time:", formatZonedDateTime(now, "America/Chicago"));6. Incorrect approaches
Using 3-letter abbreviations like CST or EST in API protocols. Assuming countries maintain fixed offsets without DST. Manually adding +8 hours via string manipulation.
7. Boundaries: date arithmetic across DST transition days
When performing calendar additions (e.g., 'add 1 day'), use calendar methods like date.setUTCDate(date.getUTCDate() + 1) or dayjs.add(1, 'day') rather than adding 86400000 ms, avoiding 23-hour or 25-hour DST anomaly days.
8. Verification
Fix IANA zones such as America/New_York and test skipped/repeated local times plus day/year boundaries. Validate zone names by constructing Intl.DateTimeFormat, then assert exact formatted parts.
9. FAQ
Why shouldn't I use UTC+8 instead of Asia/Shanghai? UTC+8 is a static offset that fails to account for historical DST shifts or future policy adjustments; IANA Asia/Shanghai encompasses full historical rules.
How do I retrieve the user's current IANA timezone on the front-end? Retrieve it via Intl.DateTimeFormat().resolvedOptions().timeZone (e.g., returns Asia/Shanghai).
What is the relationship between GMT and UTC? UTC (Coordinated Universal Time) is an atomic-clock international standard; GMT (Greenwich Mean Time) is an astronomical standard. In computing, both are practically identical, but UTC is preferred.
10. Summary
Decoupling physical UTC Instants from geographic Zone Views is key to mastering international timezones. Using IANA identifiers and Intl APIs ensures robust cross-border application behavior.
Sources and further reading
Specifications and references for checking the article’s technical details.
- RFC 3339 — Date and Time on the Internet
RFC Editor
- ECMAScript Language Specification
Ecma International
Related articles
10/13-Digit Timestamps: Year 1970 Bugs
Explain second (10-digit) vs. millisecond (13-digit) Unix timestamp unit differences in JavaScript Date parsing, providing normalization helpers.
TroubleshootingSafari Date Parsing: Invalid Dates and ISO Formats
Examine engine differences between Safari JavaScriptCore and Chrome V8 when parsing non-standard dates, providing cross-browser ISO 8601 date parsing.
Best practicesSemantic HTML: Structure Checks and SEO
Check heading order and missing image alt attributes with browser examples. Distinguish formatting, semantics, and project conventions without ranking promises.
Keep exploring
Use the related browser tool to test the workflow with your own sample data.
Open related tool