DEV Community

Cover image for IANA vs Offset-Based Time Zones: What Every Developer Should Know
Władysław Kulik
Władysław Kulik

Posted on • Edited on

IANA vs Offset-Based Time Zones: What Every Developer Should Know

"Let's meet at 3 PM UTC+2."
"Wait, is that Eastern European Time? Or Central European Summer Time?"
"Just tell me what time it is in New York."

This conversation happens in distributed teams every single day. Time zones sound simple until you actually have to work with them. And the root of most confusion comes down to two fundamentally different ways of thinking about time: IANA identifiers and UTC offsets.

The Two Approaches to Time Zones

Offset-Based: The "Simple" Way

UTC offsets seem straightforward. UTC+2 means two hours ahead of Coordinated Universal Time. UTC-5 means five hours behind. Simple math, right?

Here's how they're typically written:

  • UTC+0 (London in winter)
  • UTC-5 (New York in winter)
  • UTC+5:30 (India, year-round)
  • UTC+9 (Tokyo, year-round)

The appeal is obvious. It's just addition and subtraction. If it's 12:00 UTC, then UTC+2 is 14:00. Done.

But here's the problem: offsets don't tell the whole story.

IANA: The "Complete" Way

The IANA Time Zone Database (sometimes called the Olson database or tz database) takes a completely different approach. Instead of numbers, it uses location-based identifiers:

  • Europe/Warsaw
  • America/New_York
  • Asia/Kolkata
  • Pacific/Auckland

Each identifier represents not just a current offset, but an entire history of time changes for that location. Every daylight saving transition, every government decision to shift the country's time zone, every weird exception—it's all in there.

Why Offsets Fail (And When They Don't)

Here's a real scenario that breaks offset-based thinking.

March 10, 2024. A team schedules a daily standup at "9 AM UTC-5" with colleagues in New York.

Sounds fine. But on March 10, the US switches to daylight saving time. New York moves from UTC-5 to UTC-4.

If the calendar system stored that meeting as "9 AM UTC-5," one of two things happens:

  1. The meeting stays at the same UTC moment, so it's now 10 AM local time in New York
  2. The meeting stays at "9 AM local," but now all UTC calculations are off by an hour

Neither is what anyone wanted.

Now imagine the system used America/New_York instead.

The system knows that on March 10, 2024, at 2:00 AM, clocks jump forward. The 9 AM meeting automatically adjusts. Everyone shows up at the right time.

This is the core difference: offsets are snapshots, IANA identifiers are living rules.

When Offsets Are Actually Fine

Offsets aren't useless. They work great when:

  • Storing a specific moment in time (timestamps in databases should always be UTC)
  • Doing one-time conversions ("What time is it right now in UTC+3?")
  • The location doesn't observe daylight saving time (Arizona, for example)
  • Maximum simplicity is needed for a quick calculation

But for anything involving future dates, recurring events, or historical data—IANA is the only reliable choice.

The Weird Edge Cases That Break Everything

Time zones are full of surprises. Here are some that catch developers off guard:

Countries That Change Their Minds

Morocco has flip-flopped on daylight saving time multiple times. Egypt suspended DST, brought it back, suspended it again. Turkey switched to permanent DST in 2016, leaving its neighbors confused every spring and fall.

Hardcoding UTC+1 for Morocco means the app breaks when rules change. Using Africa/Casablanca means the IANA database updates handle it automatically.

The 30 and 45-Minute Offsets

Not all offsets are whole hours:

  • India: UTC+5:30
  • Nepal: UTC+5:45 (yes, 15 minutes different from India, just to be unique)
  • Iran: UTC+3:30
  • Afghanistan: UTC+4:30

These aren't mistakes. They're deliberate choices, often political. And they mean offsets don't always increment by hours.

The Day That Never Existed

In 2011, Samoa skipped December 30 entirely. The country jumped from December 29 directly to December 31 to move from UTC-11 to UTC+13. Anyone with a birthday on December 30 in Samoa just... didn't have one that year.

Try handling that with UTC offsets alone.

One Country, One Time Zone, Five Hours of Sun Difference

China spans five geographical time zones but uses a single official time: UTC+8 (Asia/Shanghai). When it's noon in Beijing, the sun hasn't reached its peak in Xinjiang—it's more like 10 AM by solar time.

Software built for users in western China needs to account for this cultural reality even though the "official" time zone is straightforward.

How to Actually Handle This in Code

The Wrong Way (Hardcoded Offsets)

// DON'T DO THIS
function convertToNewYork(utcDate) {
  return new Date(utcDate.getTime() - 5 * 60 * 60 * 1000);
}
Enter fullscreen mode Exit fullscreen mode

This will be wrong for half the year and completely wrong if the US ever changes its DST rules (which has happened before).

The Right Way (IANA Identifiers)

// DO THIS
function convertToNewYork(date) {
  return date.toLocaleString('en-US', { 
    timeZone: 'America/New_York' 
  });
}

// Or with modern Intl API for more control
const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'America/New_York',
  year: 'numeric',
  month: '2-digit',
  day: '2-digit',
  hour: '2-digit',
  minute: '2-digit',
  hour12: false
});

console.log(formatter.format(new Date()));
Enter fullscreen mode Exit fullscreen mode

For Serious Work: Use a Library

The native JavaScript Date object is notoriously bad with time zones. For production apps, consider:

  • Luxon—built by a long-time Moment.js contributor, excellent time zone support
  • date-fns-tz—tree-shakeable, works with date-fns
  • Day.js with timezone plugin—lightweight alternative
// Luxon example
import { DateTime } from 'luxon';

const nyTime = DateTime.now().setZone('America/New_York');
const warsawTime = DateTime.now().setZone('Europe/Warsaw');

console.log(`New York: ${nyTime.toFormat('HH:mm')}`);
console.log(`Warsaw: ${warsawTime.toFormat('HH:mm')}`);
console.log(`Difference: ${warsawTime.offset - nyTime.offset} minutes`);
Enter fullscreen mode Exit fullscreen mode

The Database Rule: Store UTC, Display Local

This is non-negotiable. In any database, timestamps should always be in UTC. Always.

-- Good
CREATE TABLE events (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255),
    start_time TIMESTAMP WITH TIME ZONE, -- Stored as UTC
    timezone VARCHAR(50)  -- e.g., 'Europe/Warsaw'
);

-- When inserting
INSERT INTO events (name, start_time, timezone) 
VALUES ('Team Standup', '2024-03-15 08:00:00+00', 'America/New_York');
Enter fullscreen mode Exit fullscreen mode

Store the user's IANA time zone separately. When displaying, convert from UTC to their local time. This way:

  • Timestamps can always be compared correctly
  • Historical data remains accurate even if time zone rules change
  • Any user can see the event in their local time

The Real-World Problem: Comparing Multiple Time Zones

Here's where theory meets reality.

Teams spread across Warsaw, New York, and San Francisco face this puzzle every week. Warsaw is UTC+1 (or UTC+2 in summer). New York is UTC-5 (or UTC-4). San Francisco is UTC-8 (or UTC-7).

That's a 9-hour spread. And twice a year, when Europe and the US switch to daylight saving time on different dates, the math gets even messier.

For a few weeks in March and November, the difference between Warsaw and New York isn't the usual 6 hours—it's 5 or 7, depending on which side of the DST transition each location is on.

Most time zone tools show one conversion at a time. But when coordinating across three or four cities, seeing everything at once becomes essential.

A Tool Built to Solve This

Understanding this problem led to creating TimeSyncer.

It's a free timezone platform that lets users compare multiple cities simultaneously—mixing IANA-based zones and offset-based zones in the same view. At a glance, it shows when 9 AM in Warsaw overlaps with working hours in New York and San Francisco.

The key feature: dragging a time slider updates all clocks together. No mental math, no switching between tabs, no "wait, did I account for DST?"

It covers 400+ time zones across 244 countries, handles all the weird edge cases (yes, including Nepal's UTC+5:45), and updates automatically when governments change their time zone rules.

For anyone regularly coordinating across time zones, give it a try. It's free, no registration required.

Key Takeaways

  1. Use IANA identifiers for anything involving future dates or recurring events. Offsets are snapshots; IANA identifiers are living rules.

  2. Store timestamps in UTC. Always. Convert to local time only for display.

  3. Don't hardcode offsets. DST rules change, governments make decisions, and code will break.

  4. Use proper libraries. Native Date objects in most languages have poor time zone support.

  5. Remember the edge cases. 30-minute offsets exist. Countries change their rules. Some places skip entire days.

  6. For multi-timezone coordination, use visual tools. The human brain isn't built for juggling multiple conversions at once.

Time zones are one of those problems that seem simple until you dig in. But with the right understanding and the right tools, they don't have to be a daily headache.


Got war stories about DST transitions breaking production? Drop a comment below.

Top comments (0)