← Blog

A Programmer's Guide to Handling Timezones in JavaScript and Python

February 5, 2026

Timezone handling is one of those things that looks simple until it isn't. Every developer has a story: the bug that only appeared twice a year, the timestamp that was off by an hour, the scheduled job that fired at the wrong time. I've had all of these, and I've helped dozens of teams fix them.

This guide covers the right way to handle timezones in JavaScript and Python — the two languages I use most in my 15 years of systems engineering work.

The Golden Rules

Before diving into code, here are the principles that prevent 90% of timezone bugs:

  1. Store timestamps in UTC — always, without exception
  2. Use IANA timezone identifiers (America/New_York, not EST or -05:00)
  3. Convert to local time only at display time — never in business logic
  4. Never do timezone math manually — use a library

JavaScript: The Right Way

The built-in: Intl.DateTimeFormat

Modern JavaScript has excellent built-in timezone support via the Intl API. You don't need moment.js for most use cases in 2026.

// Display a UTC timestamp in a specific timezone
const date = new Date('2026-03-15T14:30:00Z') // UTC

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'America/New_York',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  hour: 'numeric',
  minute: '2-digit',
  hour12: true,
})

console.log(formatter.format(date))
// "March 15, 2026 at 10:30 AM" (EST, UTC-4 in March)

Getting the current time in a timezone

// Get current time in Tokyo
const tokyoTime = new Date().toLocaleString('en-US', {
  timeZone: 'Asia/Tokyo',
  hour: 'numeric',
  minute: '2-digit',
  hour12: false,
})
console.log(tokyoTime) // e.g., "23:30"

Getting the UTC offset for a timezone

function getUtcOffsetMinutes(date, timeZone) {
  const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }))
  const tzDate = new Date(date.toLocaleString('en-US', { timeZone }))
  return (tzDate - utcDate) / 60000
}

console.log(getUtcOffsetMinutes(new Date(), 'Asia/Kolkata')) // 330 (UTC+5:30)
console.log(getUtcOffsetMinutes(new Date(), 'America/New_York')) // -240 or -300

When to use a library

For complex operations — parsing timezone-aware strings, calculating business hours, handling recurring events — use date-fns-tz (which QuickTZone itself uses):

import { formatInTimeZone, toZonedTime } from 'date-fns-tz'

const date = new Date('2026-03-15T14:30:00Z')
const formatted = formatInTimeZone(date, 'Europe/London', 'yyyy-MM-dd HH:mm zzz')
console.log(formatted) // "2026-03-15 14:30 GMT"

Avoid: moment.js (deprecated, large bundle), raw offset arithmetic, storing local times in databases.

Python: The Right Way

The built-in: zoneinfo (Python 3.9+)

Python 3.9 introduced zoneinfo, which replaces pytz for most use cases:

from datetime import datetime
from zoneinfo import ZoneInfo

# Create a UTC datetime
utc_time = datetime(2026, 3, 15, 14, 30, 0, tzinfo=ZoneInfo('UTC'))

# Convert to New York time
ny_time = utc_time.astimezone(ZoneInfo('America/New_York'))
print(ny_time)  # 2026-03-15 10:30:00-04:00

# Convert to Tokyo time
tokyo_time = utc_time.astimezone(ZoneInfo('Asia/Tokyo'))
print(tokyo_time)  # 2026-03-16 23:30:00+09:00

Getting the current time in a timezone

from datetime import datetime
from zoneinfo import ZoneInfo

# Current time in Mumbai
mumbai_now = datetime.now(ZoneInfo('Asia/Kolkata'))
print(mumbai_now.strftime('%H:%M %Z'))  # e.g., "20:00 IST"

Storing and retrieving from a database

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

# Always store in UTC
def store_event(event_time_local: datetime, user_tz: str) -> datetime:
    """Convert local time to UTC for storage."""
    if event_time_local.tzinfo is None:
        # Assume the naive datetime is in the user's timezone
        aware = event_time_local.replace(tzinfo=ZoneInfo(user_tz))
    else:
        aware = event_time_local
    return aware.astimezone(timezone.utc)

# Always display in user's timezone
def display_event(utc_time: datetime, user_tz: str) -> str:
    local_time = utc_time.astimezone(ZoneInfo(user_tz))
    return local_time.strftime('%B %d, %Y at %I:%M %p %Z')

Using pytz (Python < 3.9)

If you're on Python 3.8 or earlier, use pytz:

import pytz
from datetime import datetime

utc_time = datetime(2026, 3, 15, 14, 30, 0, tzinfo=pytz.UTC)
ny_tz = pytz.timezone('America/New_York')
ny_time = utc_time.astimezone(ny_tz)
print(ny_time)  # 2026-03-15 10:30:00-04:00

Important: With pytz, always use localize() for naive datetimes, never replace():

# WRONG - can give incorrect results during DST transitions
wrong = naive_dt.replace(tzinfo=ny_tz)

# CORRECT
correct = ny_tz.localize(naive_dt)

Common Mistakes to Avoid

Mistake Problem Fix
Storing local time in DB DST transitions corrupt data Store UTC always
Using EST instead of America/New_York Ambiguous, DST-unaware Use IANA identifiers
Manual offset arithmetic Breaks at DST boundaries Use a library
new Date('2026-03-15') in JS Parsed as UTC midnight, not local Use explicit timezone
datetime.now() without tzinfo Returns naive datetime Use datetime.now(timezone.utc)

Testing Timezone Code

Always test your timezone code around DST transition dates. In 2026:

Write tests that explicitly use these dates and verify your code handles the transitions correctly.

Manual QA Checklist for Timezone Features

When you ship a timezone-sensitive feature, test it with real city pairs rather than only offsets:

Scenario Why to test it
New York to London DST starts on different dates in the US and UK
San Francisco to Berlin Large offset and European DST rules
Mumbai to Dubai Half-hour offset next to a whole-hour offset
Tokyo to Sydney One city does not observe DST while the other can

QuickTZone is useful here even for developers: enter the same cities your users care about, move the planner date across DST boundaries, and compare the UI output with your code's output.

Author

Written by a systems engineer with 15 years of experience in distributed systems, backend development, and international software architecture.

Try QuickTZone

Plan meetings across timezones visually. Add cities, find overlap, export to calendar.

Open QuickTZone →

Latest Posts

BlogPrivacy PolicyTerms of ServiceAboutContact