AI Timestamp Converter — Timezone Handling for International Applications
Timezone bugs are among the most frustrating issues in software development. A meeting scheduled for 3 PM shows up at 3 AM. A database query misses records from an entire day. A user in Tokyo sees yesterday's date while a user in New York sees today's. These bugs are hard to reproduce, hard to test, and hard to fix — because timezone logic is genuinely complex.
The good news is that timezone handling follows clear patterns. Store timestamps in UTC, convert on display, use IANA timezone identifiers, and never calculate offsets manually. This guide walks through each pattern with practical code. The AI Timestamp Converter lets you verify conversions across timezones instantly.
The Golden Rule: Store UTC, Display Local
Every timestamp in your database should be stored in UTC (Coordinated Universal Time). UTC has no daylight saving transitions, no political timezone changes, and no ambiguity. It is the single source of truth.
// Store: always UTC
const createdAt = new Date().toISOString();
// "2026-02-23T08:30:00.000Z" (Z = UTC)
// Display: convert to user's timezone
const local = new Date(createdAt).toLocaleString('en-US', {
timeZone: 'America/New_York'
});
// "2/23/2026, 3:30:00 AM"
The conversion from UTC to local time happens at the presentation layer — in the browser, in the API response formatter, or in the email template. Never store local times in the database. If a user moves from New York to London, their historical timestamps remain correct because the raw UTC values do not change.
ISO 8601 Format
Always use ISO 8601 for timestamp serialization. It is unambiguous, sortable as a string, and universally parsed:
// Good: ISO 8601 with timezone
"2026-02-23T08:30:00Z" // UTC
"2026-02-23T03:30:00-05:00" // Eastern Time offset
// Bad: ambiguous formats
"02/23/2026 3:30 AM" // Which timezone? US or UK date format?
"1740300600" // Unix timestamp — no human readability
ISO 8601 includes the timezone offset in the string itself, so there is never ambiguity about what moment in time it represents. For API responses, always include the Z suffix or an explicit offset.
The IANA Timezone Database
Never use fixed UTC offsets like UTC+5 or GMT-8 to represent timezones. Offsets change with daylight saving time. New York is UTC-5 in winter and UTC-4 in summer. India is always UTC+5:30 — but that could change if the government decides to adopt DST.
Use IANA timezone identifiers instead:
America/New_York— automatically handles EST/EDT transitionsEurope/London— handles GMT/BST transitionsAsia/Tokyo— no DST, but the identifier is still correct if Japan ever adopts itAsia/Kolkata— handles the 30-minute offset correctlyPacific/Auckland— handles NZST/NZDT and the 13-hour offset
The IANA database (also called the Olson database or tz database) is maintained by a volunteer community and updated multiple times per year as governments change timezone rules. Your operating system, programming language runtime, and browser all ship with a copy of this database.
Storing User Timezone Preferences
Detect the user's timezone on the client side and store the IANA identifier in their profile:
// Detect browser timezone
const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
// "America/New_York"
// Store in user profile
await updateUser(userId, { timezone: userTimezone });
This lets you render server-side content (emails, PDF reports, push notifications) in the user's local time without requiring the browser.
Daylight Saving Time Pitfalls
DST transitions create two categories of bugs: the "spring forward" gap and the "fall back" overlap.
The Spring Forward Gap
When clocks spring forward (e.g., 2:00 AM becomes 3:00 AM), times between 2:00 and 3:00 do not exist in that timezone. If your application lets users schedule an event at 2:30 AM on the spring-forward date, that time is invalid.
// March 8, 2026 — US spring forward
// 2:30 AM Eastern does not exist
const invalid = new Date('2026-03-08T02:30:00-05:00');
// JavaScript silently adjusts to 3:30 AM
// Other languages may throw an error
The Fall Back Overlap
When clocks fall back (e.g., 2:00 AM becomes 1:00 AM), times between 1:00 and 2:00 occur twice. A timestamp of "1:30 AM Eastern" on the fall-back date is ambiguous — it could be EDT (before the change) or EST (after).
// November 1, 2026 — US fall back
// 1:30 AM occurs twice
// Solution: always store with UTC offset
"2026-11-01T01:30:00-04:00" // 1:30 AM EDT (first occurrence)
"2026-11-01T01:30:00-05:00" // 1:30 AM EST (second occurrence)
This is why storing UTC is critical. Both occurrences of 1:30 AM map to different UTC timestamps, so there is no ambiguity in the database.
Convert timestamps across timezones instantly
AI-powered timestamp converter with timezone comparison, Unix epoch conversion, and ISO 8601 formatting. Free and browser-based.
Try AI Timestamp Converter →The JavaScript Temporal API
The legacy Date object in JavaScript is notoriously broken for timezone work. The Temporal API, now available in modern browsers, fixes every major pain point:
// Create a timezone-aware timestamp
const meeting = Temporal.ZonedDateTime.from({
year: 2026,
month: 2,
day: 23,
hour: 15,
minute: 0,
timeZone: 'America/New_York'
});
// Convert to another timezone
const tokyoTime = meeting.withTimeZone('Asia/Tokyo');
console.log(tokyoTime.toString());
// "2026-02-24T05:00:00+09:00[Asia/Tokyo]"
// Duration-safe arithmetic
const nextWeek = meeting.add({ days: 7 });
// Correctly handles DST if the 7-day span crosses a transition
Key Temporal types for timezone work:
Temporal.Instant— an exact moment in UTC (replaces Unix timestamps)Temporal.ZonedDateTime— a moment in a specific timezone (what users see)Temporal.PlainDateTime— a date and time with no timezone (for local-only contexts like birthdays)
If you cannot use Temporal yet, libraries like date-fns-tz and luxon provide similar timezone-safe operations.
Database Timezone Patterns
PostgreSQL
PostgreSQL offers two timestamp types: TIMESTAMP (without timezone) and TIMESTAMPTZ (with timezone). Always use TIMESTAMPTZ:
CREATE TABLE events (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
starts_at TIMESTAMPTZ NOT NULL,
user_timezone TEXT NOT NULL -- IANA identifier
);
-- Insert in any timezone — PostgreSQL converts to UTC for storage
INSERT INTO events (name, starts_at, user_timezone)
VALUES ('Team Standup', '2026-02-23 09:00:00 America/New_York', 'America/New_York');
-- Query converts to the session timezone automatically
SET timezone = 'Asia/Tokyo';
SELECT starts_at FROM events;
-- Returns: 2026-02-23 23:00:00+09
MySQL
MySQL's DATETIME stores no timezone information. Use TIMESTAMP instead, which stores UTC internally and converts based on the session timezone. Alternatively, store ISO 8601 strings in a VARCHAR column if you need to preserve the original offset.
Common Timezone Mistakes
Avoid these patterns that cause timezone bugs in production:
- Using
new Date()on the server without setting the server timezone to UTC — different servers may produce different timestamps - Comparing dates as strings without normalizing to the same timezone first
- Assuming all days have 24 hours — DST transition days have 23 or 25 hours
- Using
getTimezoneOffset()as a timezone identifier — it returns a number, not an IANA name, and changes with DST - Hardcoding UTC offsets in configuration files instead of IANA identifiers
Related Tools and Resources
Build reliable timestamp handling into your workflow with these tools:
- Unix Timestamp Quick Reference for epoch conversion patterns
- Timestamp Converter Guide for Unix to human-readable conversion
- AI Crontab Generator for scheduling tasks across timezones
- AI JSON Tree Viewer for inspecting API timestamp responses
- AI Countdown Timer for timezone-aware event countdowns
Timezone handling is not optional for international applications — it is a core requirement. Store UTC, display local, use IANA identifiers, and test across DST boundaries. The AI Timestamp Converter makes it easy to verify your conversions are correct before they reach production.