Timezone API Guide for Developers: Convert Times Programmatically

Handling time zones correctly in code is infamously difficult. Between daylight saving transitions, historical offset changes, and half-hour time zones, naive implementations constantly fail. This guide covers everything you need to handle time zones reliably in your applications.

Need to test your timezone logic against real data?

Verify with GlobeTimeZone Converter →

The Golden Rule: Never Store UTC Offsets

The most common timezone mistake developers make is storing UTC offsets (like "+8" or "-5") instead of IANA timezone identifiers. Offsets change with DST — New York is UTC-4 in summer but UTC-5 in winter. Worse, governments occasionally change DST rules (e.g., Egypt delaying DST in 2023 with 3 days notice).

⚠ Common Mistake: Storing user.timezone = "+08:00"
✅ Correct: Storing user.timezone = "Asia/Shanghai"

The IANA identifier automatically resolves to the correct offset for any given date, handles DST transitions, and accounts for historical changes. Your database, your API, and your UI should all use IANA identifiers.

JavaScript/TypeScript: Native Timezone Handling

Modern JavaScript (ES2020+) has excellent built-in timezone support through Intl.DateTimeFormat. No libraries needed for basic operations:

// Get current time in any timezone
const beijingTime = new Date().toLocaleString('en-US', {
  timeZone: 'Asia/Shanghai',
  dateStyle: 'full',
  timeStyle: 'long'
});
// "Monday, May 26, 2026 at 10:24:18 PM GMT+8"

// Convert between timezones
const convertTime = (date, fromTZ, toTZ) => {
  return new Date(date.toLocaleString('en-US', { timeZone: toTZ }));
};

// Check if a timezone currently observes DST
const isDST = (tz) => {
  const jan = new Date(new Date().getFullYear(), 0, 1);
  const jul = new Date(new Date().getFullYear(), 6, 1);
  const janOffset = new Date(jan.toLocaleString('en-US', { timeZone: tz })).getTimezoneOffset();
  const julOffset = new Date(jul.toLocaleString('en-US', { timeZone: tz })).getTimezoneOffset();
  return janOffset !== julOffset;
};

// List common timezones
const commonTZs = Intl.supportedValuesOf('timeZone');
// ['Africa/Abidjan', 'Africa/Accra', ... 'Pacific/Wallis']

Using Luxon (Recommended for Complex Operations)

For date math, formatting, and cross-timezone operations, Luxon (successor to Moment.js) is the gold standard:

import { DateTime } from 'luxon';

// Create a datetime in a specific timezone
const meeting = DateTime.fromObject(
  { year: 2025, month: 6, day: 15, hour: 14, minute: 0 },
  { zone: 'America/New_York' }
);

// Convert to another timezone
const beijingView = meeting.setZone('Asia/Shanghai');
console.log(beijingView.toFormat('FF')); // "June 16, 2025 at 2:00 AM CST"

// Calculate the UTC offset at that moment
console.log(meeting.offset); // -240 (UTC-4, DST active)

// Format with timezone abbreviation
console.log(meeting.toFormat("h:mm a 'ET'")); // "2:00 PM ET"

Python: pytz, zoneinfo, and dateutil

Python 3.9+ includes the zoneinfo module (no dependencies needed). For older versions, use pytz.

# Python 3.9+ (recommended)
from zoneinfo import ZoneInfo
from datetime import datetime

# Current time in Shanghai
now_shanghai = datetime.now(ZoneInfo("Asia/Shanghai"))
print(now_shanghai)  # 2026-05-26 22:24:18.123456+08:00

# Convert between timezones
ny_time = datetime.now(ZoneInfo("America/New_York"))
shanghai_time = ny_time.astimezone(ZoneInfo("Asia/Shanghai"))
print(f"NY: {ny_time:%H:%M} | Shanghai: {shanghai_time:%H:%M}")

# Python <3.9 (with pytz)
import pytz
utc = pytz.utc.localize(datetime.utcnow())
shanghai_tz = pytz.timezone('Asia/Shanghai')
shanghai_time = utc.astimezone(shanghai_tz)

Public Timezone APIs Compared

API Free Tier Auth Required Coverage DST Data
WorldTimeAPI.orgUnlimitedNo400+ timezones✅ Yes
TimeZoneDB1,000/moAPI KeyAll IANA zones✅ Yes
Abstract Timezone API1,000/moAPI KeyGlobal✅ Yes
Google Timezone API$200 creditAPI KeyGlobal✅ Yes
IPGeolocation Timezone1,000/moAPI KeyBased on IP✅ Yes
Self-hosted IANA DBUnlimitedNoAll zones✅ Yes

WorldTimeAPI.org Example

// GET https://worldtimeapi.org/api/timezone/Asia/Shanghai
{
  "datetime": "2026-05-26T22:24:18.123456+08:00",
  "timezone": "Asia/Shanghai",
  "utc_offset": "+08:00",
  "dst": false,
  "abbreviation": "CST",
  "utc_datetime": "2026-05-26T14:24:18.123456+00:00",
  "day_of_week": 2,
  "day_of_year": 146
}

// Fetch in JavaScript
const res = await fetch('https://worldtimeapi.org/api/timezone/Asia/Shanghai');
const { datetime, utc_offset, dst, abbreviation } = await res.json();
console.log(`Shanghai: ${datetime} (${abbreviation}, ${utc_offset})`);

Handling DST Transitions

DST transitions create "impossible" and "ambiguous" times. When clocks spring forward, 2:30 AM doesn't exist. When they fall back, 1:30 AM happens twice.

Scenario Problem Solution
Spring Forward2:00-3:00 AM doesn't existSchedule meetings at safe times (avoid 1:00-3:00 AM during transitions)
Fall Back1:00-2:00 AM repeatsUse UTC internally, convert to local only for display
Sudden Policy ChangesGovernments change rulesKeep IANA tzdata updated; use a service that auto-updates
Future Date ConversionDST rules may changeUse latest tzdata; display "tentative" for far-future dates

Database Best Practices

Testing Timezone Logic

Timezone bugs are subtle and often only appear during specific dates. Here's a testing checklist:

  1. Test with DST transition dates (March 9 and November 2 for US, March 30 and October 26 for Europe)
  2. Test with time zones that have 30-minute or 45-minute offsets (India +05:30, Nepal +05:45, Chatham Islands +12:45)
  3. Test with extreme cases: Samoa (UTC-11 to UTC+13 after the 2011 date line shift), Kiribati (UTC+14)
  4. Test dates before 1970 (Unix epoch start — many implementations have bugs here)
  5. Use a dedicated timezone testing library: freezegun (Python), sinon fake timers (JavaScript)
// JavaScript: Mock time for testing
import FakeTimers from '@sinonjs/fake-timers';
const clock = FakeTimers.install({
  now: new Date('2025-03-09T07:30:00Z'), // US DST spring forward
  toFake: ['Date']
});
// Now test your timezone conversion logic
clock.uninstall();

Mastering timezone handling in your codebase prevents the kind of bugs that crash billing systems, miss flight connections, and confuse global teams. Use IANA identifiers everywhere, always store UTC, and convert to local time only at the display layer. When in doubt, verify with our free GlobeTimeZone converter or check your results against time.is.

Verify Your Timezone Implementation

Use our converter to cross-check your API results against real-time timezone data.

Open Converter →

Related Articles