Windows to IANA Time Zones in ICS: Map Them Safely

CalendarLint EditorialPublished 5 min read
Applies to: Google Calendar, Apple Calendar, Outlook

Map Windows time-zone IDs in an ICS export using a pinned CLDR release, source territory, and winter/summer checks while preserving recurrence meaning.

On this page

To map a Windows time-zone ID in an ICS file, identify the event's source territory, consult a versioned Unicode CLDR mapping, and compare the resulting time rules with the file's VTIMEZONE. Do not replace every unfamiliar TZID with a guessed city.

A name such as Pacific Standard Time is a Windows identifier, not an instruction to apply one fixed offset all year. A custom Outlook label may have no reliable name-based mapping at all.

Key Takeaways

  • Read the time-zone definition as well as every reference to its identifier.
  • CLDR's territory-specific entries matter; the global default is not evidence of the event's location.
  • Check local wall time, UTC instant, and recurrence dates across seasons.
  • Changing a label does not repair mismatched time-zone rules.

Inventory definitions and references

In a copy of the ICS, locate each VTIMEZONE and its TZID. Then find references such as:

DTSTART;TZID=Pacific Standard Time:20261110T090000
DTEND;TZID=Pacific Standard Time:20261110T093000

These are property fragments, not a complete calendar. The meaning also depends on the corresponding zone definition and the receiving implementation.

Inspect STANDARD and DAYLIGHT observances, offsets, transition rules, and their coverage. Look for references in recurring exceptions and date lists as well as ordinary start and end fields.

RFC 5545 defines how TZID references relate to time-zone components in its time-zone identifier rules. An unfamiliar spelling alone is not proof of invalid data.

Use CalendarLint's Source view to locate these fields. If the publisher's intended region is unknown, ask before choosing a replacement.

Use a pinned CLDR mapping

The examples here use the CLDR release-48 mapping file, rather than its moving main branch. That makes the example reproducible; it is not a claim that release 48 is the newest available release.

Its Windows zone mapping data, checked November 5, 2026, includes:

| Windows ID | Territory | IANA-style mapping | | --- | --- | --- | | Pacific Standard Time | 001 | America/Los_Angeles | | Pacific Standard Time | US | America/Los_Angeles | | Pacific Standard Time | CA | America/Vancouver | | US Mountain Standard Time | US | America/Phoenix | | Mountain Standard Time | US | Multiple candidates, beginning with America/Denver |

The last two rows show why substring matching is unsafe. Similar Windows names need not share seasonal behavior.

Unicode's Windows Zones specification defines 001 as the default mapping. Territory-specific rows may contain multiple space-separated identifiers; their first entry is the territory's default, not proof that it matches the event's actual location.

For a migration record, keep the CLDR release, exact Windows ID, territory, selected identifier, and reason for that selection. Also record the time-zone database version used by your conversion library.

Check a known-region example across seasons

Assume a synthetic source schedule is confirmed to mean 09:00 in Los Angeles. With the selected America/Los_Angeles rules, check at least a winter and summer date:

| Local schedule | Expected UTC instant | | --- | --- | | January 12, 2026 at 09:00 | January 12 at 17:00 UTC | | July 13, 2026 at 09:00 | July 13 at 16:00 UTC |

You can reproduce those conversions with Python 3.9 or later and an installed IANA time-zone database. If ZoneInfoNotFoundError occurs, particularly on Windows, install the first-party data package with python -m pip install tzdata. Python's zoneinfo documentation explains its system-data lookup and tzdata fallback:

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

zone = ZoneInfo("America/Los_Angeles")
for date in ("2026-01-12", "2026-07-13"):
    local = datetime.fromisoformat(date + "T09:00:00").replace(tzinfo=zone)
    print(date, local.astimezone(timezone.utc).isoformat())

Expected output:

2026-01-12 2026-01-12T17:00:00+00:00
2026-07-13 2026-07-13T16:00:00+00:00

These calculations validate the selected IANA zone on two dates. They do not prove that a particular Outlook VTIMEZONE has equivalent rules. Compare the original definition over the period your calendar actually covers.

For recurring meetings, also test dates around offset changes. A weekly 09:00 local meeting does not generally retain one UTC hour throughout the year.

Change the definition and references consistently

If the source meaning and mapping are confirmed, use a calendar library that can serialize the intended zone for your target consumer.

A coherent output must account for:

  • The zone's TZID definition.
  • DTSTART and DTEND references.
  • RECURRENCE-ID, EXDATE, and RDATE references.
  • Transition coverage for the relevant historical and future dates.

Renaming both the references and an incompatible VTIMEZONE leaves contradictory data. Removing the definition and assuming every consumer knows the new name is also not a portable repair. Prefer an appropriate zone definition and verify the target application.

Do not append Z to a local time to “convert it to UTC.” That changes its interpretation without calculating the corresponding instant.

Stop when the identifier does not identify the rules

A label such as Customized Time Zone is insufficient for automatic mapping. Preserve the original definition and ask the publisher for the intended region or a documented explanation of the custom rules.

Even a known Windows name may not establish historical equivalence over the full export range. If the event spans old rules or future transitions, compare those periods explicitly.

For a genuinely date-only all-day event, a time-zone mapping may be irrelevant. Check all-day date boundaries before applying a time conversion to a date problem.

Verify the output as calendar data

Compare the original and mapped copies. Check both wall times and UTC instants, durations, recurrence identities, exclusions, and moved occurrences. Test the destination using a temporary calendar and record its version and display zone.

CalendarLint can support source inspection and version comparison. This workflow does not assume it performs automatic Windows-to-IANA mapping or can infer a publisher's intended location.

Verification scope: CLDR release-48 rows and Unicode documentation were checked November 5, 2026. The Python winter/summer calculations were executed locally using system zoneinfo. No real Outlook export or Google import was tested; the regional scenario is synthetic.