Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)

Bug: 166295507
Merged-In: Ia304ff142efc0a4550772f5cea25ef55b781542d
Change-Id: I3c6248f1992b2d2eb1df18f1af5f75a68f8dbc16
diff --git a/README.android b/README.android
index 490de9b..72652f4 100644
--- a/README.android
+++ b/README.android
@@ -33,9 +33,10 @@
     testing/data/README for details.
 
 tzdatacheck
-  - Source code for a binary executed during boot and used to ensure that a
+  - This is for the "time zone updates via APK" feature.
+    Source code for a binary executed during boot and used to ensure that a
     device doesn't boot with incompatible/outdated time zone data installed
-    /data (as could happen if the device has just received an OTA upgrade).
+    in /data (as could happen if the device has just received an OTA upgrade).
     It is also responsible for committing staged install/uninstalls.
 
 
@@ -142,7 +143,7 @@
 
 Major version increment:
 - A non-backwards compatible change to the tzdata or tzlookup.xml files used
-  by bionic / libcore.
+  by bionic / com/android/i18n/timezone code.
 - Removal of an existing file from the distro.
 
 Minor version increment:
@@ -155,18 +156,16 @@
 Changing the Time Zone Data Set Version
 ---------------------------------------
 
-1) Modify libcore/luni/src/main/java/libcore/timezone/TzDataSetVersion.java
+1) Modify android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TzDataSetVersion.java
   - CURRENT_FORMAT_MAJOR_VERSION, CURRENT_FORMAT_MINOR_VERSION
 2) Run update-tzdata.py to regenerate the system/timezone/output_data,
    system/timezone/testing/data, external/icu runtime files and testing equivalents.
 3) Build/flash a device image with the changes and run CTS tests:
     atest CtsHostTzDataTests
-    atest CtsLibcoreTestCases
+    atest CtsIcuTestCases
 4) Run non-CTS test cases:
     atest FrameworksServicesTests:com.android.server.timezone
-5) Upload, review, submit the changes from system/timezone and libcore.
-   Note: you may have changes in external/icu/ but usually there is no need to update
-   external/icu as only a timestamp in zoneinfo64.txt should have changed.
+5) Upload, review, submit the changes from system/timezone and external/icu/.
 
 REMINDER: Any prebuilt apks / apex files (i.e. ones that that contain time zone files)
 will also need to be regenerated after this change.
diff --git a/apex/tests/src/java/android/tzdata/mts/TimeZoneRulesTest.java b/apex/tests/src/java/android/tzdata/mts/TimeZoneRulesTest.java
index 0fe9f1d..96c91d3 100644
--- a/apex/tests/src/java/android/tzdata/mts/TimeZoneRulesTest.java
+++ b/apex/tests/src/java/android/tzdata/mts/TimeZoneRulesTest.java
@@ -144,7 +144,7 @@
                 }
             }
 
-            // Sanity check that whenever a display name is just a GMT string that it's the
+            // Confidence check that whenever a display name is just a GMT string that it's the
             // right GMT string.
             String gmtDst = formatGmtString(tz, true);
             String gmtStd = formatGmtString(tz, false);
diff --git a/debug_tools/host/main/java/ZoneSplitter.java b/debug_tools/host/main/java/ZoneSplitter.java
index a8b72e6..3840df6 100644
--- a/debug_tools/host/main/java/ZoneSplitter.java
+++ b/debug_tools/host/main/java/ZoneSplitter.java
@@ -62,7 +62,7 @@
         // byte[12] tzdata_version  -- "tzdata2012f\0"
         // int index_offset
         // int data_offset
-        // int zonetab_offset
+        // int final_offset
         writeVersionFile(mappedFile, outputDir);
 
         final int fileSize = (int) tzData.length();
@@ -70,12 +70,13 @@
         validateOffset(index_offset, fileSize);
         int data_offset = mappedFile.getInt();
         validateOffset(data_offset, fileSize);
-        int zonetab_offset = mappedFile.getInt();
-        validateOffset(zonetab_offset, fileSize);
+        int final_offset = mappedFile.getInt();
 
-        if (index_offset >= data_offset || data_offset >= zonetab_offset) {
+        if (index_offset >= data_offset
+                || data_offset >= final_offset
+                || final_offset > fileSize) {
             throw new IOException("Invalid offset: index_offset=" + index_offset
-                    + ", data_offset=" + data_offset + ", zonetab_offset=" + zonetab_offset
+                    + ", data_offset=" + data_offset + ", final_offset=" + final_offset
                     + ", fileSize=" + fileSize);
         }
 
@@ -83,7 +84,12 @@
         zicFilesDir.mkdir();
         extractZicFiles(mappedFile, index_offset, data_offset, zicFilesDir);
 
-        writeZoneTabFile(mappedFile, zonetab_offset, fileSize - zonetab_offset, outputDir);
+        if (final_offset != fileSize) {
+            // This isn't an error, but it's worth noting: it suggests the file may be in a newer
+            // format than the current branch.
+            System.out.println(
+                    "final_offset (" + final_offset + ") != fileSize (" + fileSize + ")");
+        }
     }
 
     static MappedByteBuffer createMappedByteBuffer(File tzData) throws IOException {
@@ -174,7 +180,8 @@
                 if (ids[i].compareTo(ids[i - 1]) <= 0) {
                     throw new IOException(
                             "Index not sorted or contains multiple entries with the same ID"
-                            + ", index=" + i + ", ids[i]=" + ids[i] + ", ids[i - 1]=" + ids[i - 1]);
+                                    + ", index=" + i + ", ids[i]=" + ids[i]
+                                    + ", ids[i - 1]=" + ids[i - 1]);
                 }
             }
         }
@@ -192,14 +199,6 @@
         }
     }
 
-    private static void writeZoneTabFile(MappedByteBuffer mappedFile,
-            int zoneTabOffset, int zoneTabSize, File outputDir) throws IOException {
-        byte[] bytes = new byte[zoneTabSize];
-        mappedFile.position(zoneTabOffset);
-        mappedFile.get(bytes, 0, bytes.length);
-        writeBytesToFile(new File(outputDir, "zone.tab"), bytes);
-    }
-
     private static void writeStringUtf8ToFile(File file, String string) throws IOException {
         writeBytesToFile(file, string.getBytes(StandardCharsets.UTF_8));
     }
diff --git a/input_tools/android/tzids/Android.bp b/input_tools/android/tzids/Android.bp
new file mode 100644
index 0000000..c4750c8
--- /dev/null
+++ b/input_tools/android/tzids/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Proto library
+java_library_host {
+    name: "tzids_protos",
+
+    proto: {
+        type: "full",
+        include_dirs: ["external/protobuf/src"],
+    },
+
+    srcs: ["src/main/proto/**/*.proto"],
+}
+
+java_library_host {
+    name: "tzids",
+    srcs: ["src/main/java/**/*.java"],
+    static_libs: ["tzids_protos"],
+}
+
+java_test_host {
+    name: "tzids_tests",
+
+    srcs: ["src/test/java/**/*.java"],
+    static_libs: [
+        "junit",
+        "tzids",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/input_tools/android/tzids/TEST_MAPPING b/input_tools/android/tzids/TEST_MAPPING
new file mode 100644
index 0000000..89921f9
--- /dev/null
+++ b/input_tools/android/tzids/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+  "presubmit": [
+    {
+      "name" : "tzids_tests",
+      "host" : true
+    }
+  ]
+}
diff --git a/input_tools/android/tzids/src/main/java/com/android/timezone/tzids/TimeZoneIds.java b/input_tools/android/tzids/src/main/java/com/android/timezone/tzids/TimeZoneIds.java
new file mode 100644
index 0000000..cc35e17
--- /dev/null
+++ b/input_tools/android/tzids/src/main/java/com/android/timezone/tzids/TimeZoneIds.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.timezone.tzids;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.stream.Collectors.toMap;
+
+import com.android.timezone.tzids.proto.TzIdsProto;
+import com.google.protobuf.TextFormat;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * A representation of Android's country ISO code mapping for TZDB time zone IDs, and information
+ * about time zone ID equivalence, for use in host tooling.
+ *
+ * <p>The Android team maintain the mapping based on information from IANA's TZDB and other
+ * sources. Strictly speaking, TZDB no longer supports the idea of a time zone ID being associated
+ * with a single country (see zone1970.tab Vs zone.tab), but Android requires most zones be mapped
+ * this way: Android has a region-based time zone picker in settings (for selecting the device's
+ * time zone manually), and it uses a country-based algorithm for telephony-based time zone
+ * detection. Most time zone IDs in TZDB have an exemplar location, and a time zone ID will be
+ * mapped to the country of that exemplar location.
+ *
+ * <p>Besides the country mapping, only some IDs for a country are actually "useful". The others are
+ * associated with equivalent alternatives that are preferred. Mappings between different time zone
+ * IDs exist in two main situations:
+ * <ol>
+ *     <li>"Links" : When TZDB has a direct link / synonym. e.g. "GB-Eire", an old ID, maps to
+ *     "Europe/London", the modern / canonical equivalent. "GB-Eire" and "Europe/London" are
+ *     identical in TZDB. Note: Other libraries with additional metadata like ICU could still treat
+ *     "GB-Eire" differently from "Europe/London".
+ *     These will typically be as you'd expect from looking at the IANA tzdb backward file. However,
+ *     the IDs preferred by Android are determined by countryzones.txt, which could choose to
+ *     continue using an old ID, in which case the link may be reversed. This reversal is expected
+ *     when an older version of ICU doesn't have strings for a new ID.</li>
+ *     <li>"Replacements" : When zones have coalesced over time within a country. TZDB has many
+ *     "extra" IDs for time zones because of historical differences that haven't been relevant for
+ *     years. Replacements have a "from" time which indicates the point in time after which the two
+ *     zones can be considered equivalent. e.g. "America/Boise" has the same rules as
+ *     "America/Phoenix" after Sun, 03 Feb 1974, so the two can be considered equivalent today, but
+ *     not for dates before then.</li>
+ * </ol>
+ *
+ * <p>Other notes:
+ * <ul>
+ *     <li>There are entries in TZDB that are not mapped to a country and so are not included.
+ *     e.g. Etc/GMT+5.</li>
+ *     <li>Time zone IDs must be mapped to at most one country.</li>
+ *     <li>There are many time zone IDs in TZDB that have identical rules, but are associated with
+ *     different countries. These are deliberately not recorded as links or replacements.
+ *     i.e. Links/replacements do not link across ISO country codes.</li>
+ * </ul>
+ */
+public class TimeZoneIds {
+
+    private final TzIdsProto.TimeZoneIds mTimeZoneIdsProto;
+
+    /** Creates a {@link TimeZoneIds} from the proto definition. */
+    public TimeZoneIds(TzIdsProto.TimeZoneIds timeZoneIdsProto) {
+        mTimeZoneIdsProto = Objects.requireNonNull(timeZoneIdsProto);
+    }
+
+    /** Loads the {@code inputFile} as a {@link TimeZoneIds}. */
+    public static TimeZoneIds load(File inputFile) throws IOException {
+        TzIdsProto.TimeZoneIds.Builder builder = TzIdsProto.TimeZoneIds.newBuilder();
+        try (InputStreamReader reader =
+                new InputStreamReader(new FileInputStream(inputFile), UTF_8)) {
+            TextFormat.getParser().merge(reader, builder);
+        }
+        return new TimeZoneIds(builder.build());
+    }
+
+    /** Store this in {@code file}. */
+    public void store(File file) throws IOException {
+        try (OutputStreamWriter writer =
+                new OutputStreamWriter(new FileOutputStream(file), UTF_8)) {
+            writer.append("# Autogenerated file - DO NOT EDIT.\n");
+            TextFormat.print(mTimeZoneIdsProto, writer);
+        }
+    }
+
+    /**
+     * Returns the country code associated with the supplied {@code zoneId} or {@code null} if it
+     * is not found.
+     */
+    public String getCountryCodeForZoneId(String zoneId) {
+        for (TzIdsProto.CountryMapping countryMapping
+                : mTimeZoneIdsProto.getCountryMappingsList()) {
+            if (countryMapping.getTimeZoneIdsList().contains(zoneId)) {
+                return countryMapping.getIsoCode();
+            }
+
+            for (TzIdsProto.TimeZoneLink timeZoneLink : countryMapping.getTimeZoneLinksList()) {
+                if (timeZoneLink.getAlternativeId().equals(zoneId)) {
+                    return countryMapping.getIsoCode();
+                }
+            }
+
+            for (TzIdsProto.TimeZoneReplacement timeZoneReplacement
+                    : countryMapping.getTimeZoneReplacementsList()) {
+                if (timeZoneReplacement.getReplacedId().equals(zoneId)) {
+                    return countryMapping.getIsoCode();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a country mapping for TZDB time zone IDs on or after the specified time.
+     * The {@link Map} returned contains entries that link Olson IDs to themselves, or to preferred
+     * Olson IDs. The {@code replacementThreshold} is used to identify which "replacements" should
+     * be considered (see {@link TimeZoneIds} for details).
+     *
+     * <p>This mapping is useful when interpreting data from third party sources that could use any
+     * of the many equivalent zone IDs from TZDB and need to interact with Android devices.
+     *
+     * <p>If no map entry is present for an ID, then the IDs is either not valid or is not mapped to
+     * the ISO country code by Android's mapping data.
+     *
+     * @param isoCode the ISO 3166 alpha-2 country code for the country
+     * @param replacementThreshold the point in time to use when interpreting replacements
+     * @throws IllegalArgumentException if the country code is not recognized
+     */
+    public Map<String, String> getCountryIdMap(String isoCode, Instant replacementThreshold) {
+        for (TzIdsProto.CountryMapping countryMapping
+                : mTimeZoneIdsProto.getCountryMappingsList()) {
+            if (countryMapping.getIsoCode().equalsIgnoreCase(isoCode)) {
+                return createCountryIdMap(countryMapping, replacementThreshold);
+            }
+        }
+        throw new IllegalArgumentException("Unknown country code: " + isoCode);
+    }
+
+    private Map<String, String> createCountryIdMap(
+            TzIdsProto.CountryMapping countryMapping, Instant replacementThreshold) {
+        Map<String, String> tzIdMap = new HashMap<>();
+
+        // Add identity entries for the preferred IDs.
+        putAllSafely(tzIdMap, countryMapping.getTimeZoneIdsList()
+                .stream()
+                .collect(toMap(Function.identity(), Function.identity())));
+
+        // Handle links: just add straightforward map entries.
+        putAllSafely(tzIdMap, countryMapping.getTimeZoneLinksList()
+                .stream()
+                .collect(toMap(x -> x.getAlternativeId(), x -> x.getPreferredId())));
+
+        // Handle replacements: either add the replacementId or replacedId depending on the
+        // replacementThreshold.
+        putAllSafely(tzIdMap, countryMapping.getTimeZoneReplacementsList()
+                .stream()
+                .collect(toMap(x -> x.getReplacedId(), x -> {
+                    if (x.getFromMillis() <= replacementThreshold.toEpochMilli()) {
+                        return x.getReplacementId();
+                    } else {
+                        return x.getReplacedId();
+                    }
+                })));
+        return tzIdMap;
+    }
+
+    /**
+     * Like {@link Map#putAll(Map)} but throws an exception if {@code sourceMap} contains a key
+     * already present in {@code targetMap}.
+     */
+    private static void putAllSafely(Map<String, String> targetMap, Map<String, String> sourceMap) {
+        for (Map.Entry<String, String> entry : sourceMap.entrySet()) {
+            String oldMapping = targetMap.put(entry.getKey(), entry.getValue());
+            if (oldMapping != null) {
+                throw new IllegalArgumentException("Key is not unique: "
+                        + entry.getKey() + " maps to both "
+                        + entry.getValue() + " and " + oldMapping);
+            }
+        }
+    }
+}
diff --git a/input_tools/android/tzids/src/main/proto/tz_ids_proto.proto b/input_tools/android/tzids/src/main/proto/tz_ids_proto.proto
new file mode 100644
index 0000000..e92aae9
--- /dev/null
+++ b/input_tools/android/tzids/src/main/proto/tz_ids_proto.proto
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+option java_package = "com.android.timezone.tzids.proto";
+option java_multiple_files = false;
+
+package com.android.timezone.tzids.proto;
+
+// Information about Olson IDs used / preferred by Android.
+message TimeZoneIds {
+    // The IANA TZDB version the data was generated from.
+    optional string ianaVersion = 1;
+
+    // Information about IDs that are mapped to ISO 3166 Alpha-2 country codes.
+    repeated CountryMapping countryMappings = 2;
+}
+
+// Information about Olson IDs recognized by Android as being related to a country.
+message CountryMapping {
+    // The ISO 3166 Alpha-2 country code.
+    required string isoCode = 1;
+
+    // The IANA TZDB Olson IDs preferred by Android for the country.
+    repeated string timeZoneIds = 2;
+
+    // Links for time zones that are recognized as being for the country, but are not preferred.
+    // These links are for time zones that have always been equivalent.
+    // e.g. "GB-Eire" is linked to "Europe/London" because "GB-Eire"" is just an obsoleted synonym.
+    repeated TimeZoneLink timeZoneLinks = 3;
+
+    // Replacements for time zones where the replaced time zone is not identical to the replacement
+    // before some point in time. After that point in time, the two zones have been judged as
+    // equivalent. e.g. "America/Boise" has the same rules as "America/Phoenix" after Sun, 03 Feb
+    // 1974, so the two can be considered equivalent today, but not for dates before that.
+    repeated TimeZoneReplacement timeZoneReplacements = 4;
+}
+
+// An ID replacement when one time zone Olson ID is just direct synonym for another.
+message TimeZoneLink {
+    // The alternative Olson ID. This will typically be an obsoleted Olson ID.
+    required string alternativeId = 1;
+    // The Android preferred Olson ID. This will typically be a newer / more correct Olson ID.
+    required string preferredId = 2;
+}
+
+// The functional replacement of one time zone ID by another after a point in time.
+// Computed by looking at offset behavior / zone metadata.
+message TimeZoneReplacement {
+    // The Olson ID that was replaced / ceased to be distinct.
+    required string replacedId = 1;
+    // The Olson ID that is better / to use in place of replacedId on Android after fromMillis.
+    required string replacementId = 2;
+    // When replacementId replaced replacedId. Milliseconds from the start of the Unix epoch.
+    required int64 fromMillis = 3;
+}
diff --git a/input_tools/android/tzids/src/test/java/com/android/timezone/tzids/TimeZoneIdsTest.java b/input_tools/android/tzids/src/test/java/com/android/timezone/tzids/TimeZoneIdsTest.java
new file mode 100644
index 0000000..7d8fb63
--- /dev/null
+++ b/input_tools/android/tzids/src/test/java/com/android/timezone/tzids/TimeZoneIdsTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.timezone.tzids;
+
+import static java.time.ZoneOffset.UTC;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import com.android.timezone.tzids.proto.TzIdsProto;
+import org.junit.Test;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Tests for {@link TimeZoneIds}. */
+public final class TimeZoneIdsTest {
+
+    @Test
+    public void getCountryIdMap_links() throws Exception {
+        TzIdsProto.TimeZoneIds.Builder tzIdsBuilder = TzIdsProto.TimeZoneIds.newBuilder();
+
+        TzIdsProto.CountryMapping gb = TzIdsProto.CountryMapping.newBuilder()
+                .setIsoCode("gb")
+                .addTimeZoneIds("Europe/London")
+                .addTimeZoneLinks(createLink("GB", "Europe/London"))
+                .build();
+        tzIdsBuilder.addCountryMappings(gb);
+
+        TimeZoneIds tzIds = new TimeZoneIds(tzIdsBuilder.build());
+
+        Map<String, String> expectedMap = new HashMap<>();
+        expectedMap.put("Europe/London", "Europe/London");
+        expectedMap.put("GB", "Europe/London");
+
+        assertEquals(expectedMap, tzIds.getCountryIdMap("Gb", Instant.EPOCH));
+        assertEquals(expectedMap, tzIds.getCountryIdMap("GB", Instant.EPOCH));
+        assertEquals(expectedMap, tzIds.getCountryIdMap("gB", Instant.EPOCH));
+
+        assertEquals(expectedMap, tzIds.getCountryIdMap("gb", Instant.MIN));
+        assertEquals(expectedMap, tzIds.getCountryIdMap("gb", Instant.EPOCH));
+        assertEquals(expectedMap, tzIds.getCountryIdMap("gb", Instant.MAX));
+    }
+
+    @Test
+    public void getCountryIdMap_replacements() throws Exception {
+        TzIdsProto.TimeZoneIds.Builder tzIdsBuilder = TzIdsProto.TimeZoneIds.newBuilder();
+
+        // A much-simplified version of the US time zone IDs.
+        Instant boiseFrom = LocalDateTime.of(1974, Month.FEBRUARY, 3, 9, 0).toInstant(UTC);
+        Instant dakotaFrom = LocalDateTime.of(1992, Month.OCTOBER, 25, 8, 0).toInstant(UTC);
+        TzIdsProto.CountryMapping us = TzIdsProto.CountryMapping.newBuilder()
+                .setIsoCode("us")
+                .addTimeZoneIds("America/Phoenix")
+                .addTimeZoneIds("America/Chicago")
+                .addTimeZoneReplacements(
+                        createReplacement("America/Boise", "America/Phoenix", boiseFrom))
+                .addTimeZoneReplacements(
+                        createReplacement(
+                                "America/North_Dakota/Center", "America/Chicago", dakotaFrom))
+                .build();
+        tzIdsBuilder.addCountryMappings(us);
+
+        TimeZoneIds tzIds = new TimeZoneIds(tzIdsBuilder.build());
+
+        Map<String, String> baseExpectedMap = new HashMap<>();
+        baseExpectedMap.put("America/Phoenix", "America/Phoenix");
+        baseExpectedMap.put("America/Chicago", "America/Chicago");
+
+        // Before all replacements in effect.
+        {
+            Map<String, String> expectedMap = new HashMap<>(baseExpectedMap);
+            expectedMap.put("America/Boise", "America/Boise");
+            expectedMap.put("America/North_Dakota/Center", "America/North_Dakota/Center");
+
+            assertEquals(expectedMap, tzIds.getCountryIdMap("us", Instant.EPOCH));
+            assertEquals(expectedMap, tzIds.getCountryIdMap("us", boiseFrom.minusMillis(1)));
+        }
+
+        // One replacement in effect.
+        {
+            Map<String, String> expectedMap = new HashMap<>(baseExpectedMap);
+            expectedMap.put("America/Boise", "America/Phoenix");
+            expectedMap.put("America/North_Dakota/Center", "America/North_Dakota/Center");
+
+            assertEquals(expectedMap, tzIds.getCountryIdMap("us", boiseFrom));
+            assertEquals(expectedMap, tzIds.getCountryIdMap("us", dakotaFrom.minusMillis(1)));
+        }
+
+        // All replacements in effect.
+        {
+            Map<String, String> expectedMap = new HashMap<>(baseExpectedMap);
+            expectedMap.put("America/Boise", "America/Phoenix");
+            expectedMap.put("America/North_Dakota/Center", "America/Chicago");
+
+            assertEquals(expectedMap, tzIds.getCountryIdMap("us", dakotaFrom));
+            assertEquals(expectedMap,
+                    tzIds.getCountryIdMap("us", Instant.ofEpochMilli(Long.MAX_VALUE)));
+        }
+    }
+
+    @Test
+    public void getCountryCodeForZoneId() {
+        TzIdsProto.TimeZoneIds.Builder tzIdsBuilder = TzIdsProto.TimeZoneIds.newBuilder();
+
+        TzIdsProto.CountryMapping gb = TzIdsProto.CountryMapping.newBuilder()
+                .setIsoCode("gb")
+                .addTimeZoneIds("Europe/London")
+                .addTimeZoneLinks(createLink("GB", "Europe/London"))
+                .build();
+        tzIdsBuilder.addCountryMappings(gb);
+
+        Instant boiseFrom = LocalDateTime.of(1974, Month.FEBRUARY, 3, 9, 0).toInstant(UTC);
+        TzIdsProto.CountryMapping us = TzIdsProto.CountryMapping.newBuilder()
+                .setIsoCode("us")
+                .addTimeZoneIds("America/Phoenix")
+                .addTimeZoneLinks(createLink("US/Arizona", "America/Phoenix"))
+                .addTimeZoneReplacements(
+                        createReplacement("America/Boise", "America/Phoenix", boiseFrom))
+                .build();
+        tzIdsBuilder.addCountryMappings(us);
+
+        TimeZoneIds tzIds = new TimeZoneIds(tzIdsBuilder.build());
+        assertNull(tzIds.getCountryCodeForZoneId("FooBar"));
+        assertEquals("gb", tzIds.getCountryCodeForZoneId("GB"));
+        assertEquals("gb", tzIds.getCountryCodeForZoneId("Europe/London"));
+        assertEquals("us", tzIds.getCountryCodeForZoneId("America/Phoenix"));
+        assertEquals("us", tzIds.getCountryCodeForZoneId("US/Arizona"));
+        assertEquals("us", tzIds.getCountryCodeForZoneId("America/Boise"));
+    }
+
+    private static TzIdsProto.TimeZoneLink createLink(
+            String alternativeId, String preferredId) {
+        return TzIdsProto.TimeZoneLink.newBuilder()
+                .setAlternativeId(alternativeId)
+                .setPreferredId(preferredId)
+                .build();
+    }
+
+    private static TzIdsProto.TimeZoneReplacement createReplacement(String replacedId,
+            String replacementId, Instant from) {
+        return TzIdsProto.TimeZoneReplacement.newBuilder()
+                .setReplacedId(replacedId)
+                .setReplacementId(replacementId)
+                .setFromMillis(from.toEpochMilli())
+                .build();
+    }
+}
diff --git a/input_tools/android/tzlookup_generator/Android.bp b/input_tools/android/tzlookup_generator/Android.bp
index 3ebd323..cc15ada 100644
--- a/input_tools/android/tzlookup_generator/Android.bp
+++ b/input_tools/android/tzlookup_generator/Android.bp
@@ -14,7 +14,7 @@
 
 // Proto library
 java_library_host {
-    name: "countryzonesprotos",
+    name: "countryzones_protos",
 
     proto: {
         type: "full",
@@ -29,9 +29,9 @@
 
     srcs: ["src/main/java/**/*.java"],
     static_libs: [
+        "countryzones_protos",
         "icu4j",
-        "countryzonesprotos",
-        "libprotobuf-java-full",
+        "tzids",
         "tztools_common",
     ],
 }
diff --git a/input_tools/android/tzlookup_generator/README.android b/input_tools/android/tzlookup_generator/README.android
index 4c993d4..fbb4ac8 100644
--- a/input_tools/android/tzlookup_generator/README.android
+++ b/input_tools/android/tzlookup_generator/README.android
@@ -1,2 +1,12 @@
-This tool generates the tzlookup.xml file from the countryzones.txt (proto text) file.
-The tool also uses ICU4J and IANA data to synthesize some time zone metadata.
+This tool generates the tzlookup.xml file from the countryzones.txt (proto
+text) file. tzlookup.xml is used to associate zones with regions/countries. The
+tool uses ICU4J and IANA data to synthesize some time zone metadata.
+
+Besides tzlookup.xml, the tool also generates a tzids.prototxt file
+containing information about zone IDs, id links and "functionally identical"
+zones[1] within each known country. These can be used to map time zone IDs to
+Android's preferred set. This duplicates information from the tzlookup.xml, but
+it is easier to use from host tools than Android's tzlookup.xml's format.
+
+[1] i.e. zones that differed in the past but were "folded in" to other zones
+and are not distinct for future times according to IANA or ICU/CLDR.
diff --git a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/BackwardFile.java b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/BackwardFile.java
index 161a6b8..95bbbf2 100644
--- a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/BackwardFile.java
+++ b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/BackwardFile.java
@@ -22,16 +22,20 @@
 import java.text.ParseException;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
- * A class that knows about the structure of the backward file.
+ * A class that knows about the structure of the IANA tzdb backward file.
  */
 final class BackwardFile {
 
     private final Map<String, String> links = new HashMap<>();
+    private Map<String, String> directLinks;
 
     private BackwardFile() {}
 
@@ -70,30 +74,69 @@
         }
     }
 
-    /** Returns a mapping from linkName (old tz ID) to target (new tz ID). */
-    Map<String, String> getDirectLinks() {
-        // Validate links for cycles and collapse the links if there are links to links. There's a
-        // simple check to confirm that no chain is longer than a fixed length, to guard against
-        // cycles.
-        final int maxChainLength = 2;
-        Map<String, String> collapsedLinks = new HashMap<>();
-        for (String fromId : links.keySet()) {
-            int chainLength = 0;
-            String currentId = fromId;
-            String lastId = null;
-            while ((currentId = links.get(currentId)) != null) {
-                chainLength++;
-                lastId = currentId;
-                if (chainLength >= maxChainLength) {
-                    throw new IllegalStateException(
-                            "Chain from " + fromId + " is longer than " + maxChainLength);
+    /**
+     * Returns a set of IDs linked to the supplied ID, even intermediate ones in a chain of links.
+     */
+    Set<String> getAllAlternativeIds(String zoneId) {
+        Set<String> knownAlternativeIds = new HashSet<>();
+        // Add the ID we're searching for. We don't need to look for it.
+        knownAlternativeIds.add(zoneId);
+
+        LinkedList<String> searchIdQueue = new LinkedList<>();
+        searchIdQueue.add(zoneId);
+        while (!searchIdQueue.isEmpty()) {
+            String searchId = searchIdQueue.removeLast();
+            for (Map.Entry<String, String> entry : links.entrySet()) {
+                String fromId = entry.getKey();
+                String toId = entry.getValue();
+                if (fromId.equals(searchId)) {
+                    if (knownAlternativeIds.add(toId)) {
+                        searchIdQueue.add(toId);
+                    }
+                } else if (toId.equals(searchId)) {
+                    if (knownAlternativeIds.add(fromId)) {
+                        searchIdQueue.add(fromId);
+                    }
                 }
             }
-            if (chainLength == 0) {
-                throw new IllegalStateException("Null Link targetId for " + fromId);
-            }
-            collapsedLinks.put(fromId, lastId);
         }
-        return Collections.unmodifiableMap(collapsedLinks);
+
+        // Remove the zone we were searching for - it's not an alternative for itself.
+        knownAlternativeIds.remove(zoneId);
+        return Collections.unmodifiableSet(knownAlternativeIds);
+    }
+
+    Map<String, String> getLinks() {
+        return Collections.unmodifiableMap(links);
+    }
+
+    /** Returns a mapping from linkName (old tz ID) to target (new tz ID). */
+    Map<String, String> getDirectLinks() {
+        if (directLinks == null) {
+            // Validate links for cycles and collapse the links to remove intermediates if there are
+            // links to links. There's a simple check to confirm that no chain is longer than a
+            // fixed length, to guard against cycles.
+            final int maxChainLength = 2;
+            Map<String, String> collapsedLinks = new HashMap<>();
+            for (String fromId : links.keySet()) {
+                int chainLength = 0;
+                String currentId = fromId;
+                String lastId = null;
+                while ((currentId = links.get(currentId)) != null) {
+                    chainLength++;
+                    lastId = currentId;
+                    if (chainLength > maxChainLength) {
+                        throw new IllegalStateException(
+                                "Chain from " + fromId + " is longer than " + maxChainLength);
+                    }
+                }
+                if (chainLength == 0) {
+                    throw new IllegalStateException("Null Link targetId for " + fromId);
+                }
+                collapsedLinks.put(fromId, lastId);
+            }
+            directLinks = Collections.unmodifiableMap(collapsedLinks);
+        }
+        return directLinks;
     }
 }
diff --git a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/CountryZonesFileSupport.java b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/CountryZonesFileSupport.java
index 9f9ad77..2c82cb4 100644
--- a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/CountryZonesFileSupport.java
+++ b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/CountryZonesFileSupport.java
@@ -15,7 +15,7 @@
  */
 package com.android.libcore.timezone.tzlookup;
 
-import com.android.libcore.timezone.tzlookup.proto.CountryZonesFile;
+import com.android.libcore.timezone.countryzones.proto.CountryZonesFile;
 import com.google.protobuf.TextFormat;
 
 import java.io.BufferedReader;
diff --git a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupFile.java b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupFile.java
index d29de56..446b857 100644
--- a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupFile.java
+++ b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupFile.java
@@ -15,6 +15,7 @@
  */
 package com.android.libcore.timezone.tzlookup;
 
+import com.android.timezone.tzids.proto.TzIdsProto;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
@@ -25,6 +26,8 @@
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
+
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
@@ -60,6 +63,10 @@
     private static final String ZONE_SHOW_IN_PICKER_ATTRIBUTE = "picker";
     // The time when the zone stops being distinct from another of the country's zones (inclusive).
     private static final String ZONE_NOT_USED_AFTER_ATTRIBUTE = "notafter";
+    // The zone ID used in place of this one starting from the "notafter" time (when present).
+    private static final String ZONE_NOT_USED_REPLACEMENT_ID_ATTRIBUTE = "repl";
+    // Other IDs associated with this ID, e.g. legacy or more modern alternatives.
+    private static final String ZONE_ALTERNATIVE_IDS_ATTRIBUTE = "alts";
 
 
     // Short encodings for boolean attributes.
@@ -71,20 +78,17 @@
         /*
          * The required XML structure is:
          * <timezones ianaversion="2017b">
-         *   <countryzones>
-         *     <country code="us" default="America/New_York" everutc="n">
-         *       <!-- -5:00 -->
-         *       <id notafter="1234">America/New_York"</id>
-         *       ...
-         *       <!-- -8:00 -->
-         *       <id picker="n">America/Los_Angeles</id>
-         *       ...
-         *     </country>
-         *     <country code="gb" default="Europe/London" defaultBoost="y" everutc="y">
-         *       <!-- 0:00 -->
-         *       <id>Europe/London</id>
-         *     </country>
-         *   </countryzones>
+         *  <countryzones>
+         *   <country code="us" default="America/New_York" everutc="n">
+         *    <id>America/New_York"</id>
+         *    <id notafter="1234" repl="America/New_York" alts="US/Michigan">America/Detroit"</id>
+         *    ...
+         *    <id picker="n">America/Los_Angeles</id>
+         *   </country>
+         *   <country code="gb" default="Europe/London" defaultBoost="y" everutc="y">
+         *    <id alts="Europe/Belfast,GB,GB-Eire">Europe/London</id>
+         *   </country>
+         *  </countryzones>
          * </timezones>
          */
 
@@ -167,7 +171,7 @@
         private final String defaultTimeZoneId;
         private final boolean defaultTimeZoneBoost;
         private final boolean everUsesUtc;
-        private final List<TimeZoneMapping> timeZoneIds = new ArrayList<>();
+        private final List<TimeZoneMapping> timeZoneMappings = new ArrayList<>();
 
         Country(String isoCode, String defaultTimeZoneId, boolean defaultTimeZoneBoost,
                 boolean everUsesUtc) {
@@ -177,8 +181,47 @@
             this.everUsesUtc = everUsesUtc;
         }
 
-        void addTimeZoneIdentifier(TimeZoneMapping timeZoneId) {
-            timeZoneIds.add(timeZoneId);
+        void addTimeZoneMapping(TimeZoneMapping timeZoneMapping) {
+            timeZoneMappings.add(timeZoneMapping);
+        }
+
+        static TzIdsProto.CountryMapping createCountryMappingProto(Country country) {
+            TzIdsProto.CountryMapping.Builder countryMappingBuilder =
+                    TzIdsProto.CountryMapping.newBuilder()
+                            .setIsoCode(country.isoCode);
+            for (TzLookupFile.TimeZoneMapping timeZoneMapping : country.timeZoneMappings) {
+                String mappingTimeZoneId = timeZoneMapping.olsonId;
+                String notUsedReplacementId = timeZoneMapping.notAfterReplacementId;
+                Instant notUsedAfterInstant = timeZoneMapping.notUsedAfterInclusive;
+                if (notUsedReplacementId == null && notUsedAfterInstant == null) {
+                    countryMappingBuilder.addTimeZoneIds(mappingTimeZoneId);
+                } else if (notUsedReplacementId != null && notUsedAfterInstant != null) {
+                    String replacedTimeZoneId = mappingTimeZoneId;
+                    TzIdsProto.TimeZoneReplacement timeZoneReplacement =
+                            TzIdsProto.TimeZoneReplacement.newBuilder()
+                                    .setReplacedId(replacedTimeZoneId)
+                                    .setReplacementId(notUsedReplacementId)
+                                    .setFromMillis(notUsedAfterInstant.toEpochMilli())
+                                    .build();
+                    countryMappingBuilder.addTimeZoneReplacements(timeZoneReplacement);
+                } else {
+                    throw new IllegalArgumentException(
+                            "Malformed TimeZoneMapping:" + timeZoneMapping);
+                }
+
+                for (String alternativeZoneId : timeZoneMapping.alternativeZoneIds) {
+                    // We could collapse links when notUsedReplacementId != null by using it instead
+                    // of mappingTimeZoneId below, but that would potentially lose information.
+                    // Leave it to the downstream components to collapse links if they want to.
+                    TzIdsProto.TimeZoneLink timeZoneLink =
+                            TzIdsProto.TimeZoneLink.newBuilder()
+                                    .setPreferredId(mappingTimeZoneId)
+                                    .setAlternativeId(alternativeZoneId)
+                                    .build();
+                    countryMappingBuilder.addTimeZoneLinks(timeZoneLink);
+                }
+            }
+            return countryMappingBuilder.build();
         }
 
         static void writeXml(Country country, XMLStreamWriter writer)
@@ -192,8 +235,8 @@
             }
             writer.writeAttribute(EVER_USES_UTC_ATTRIBUTE, encodeBooleanAttribute(
                     country.everUsesUtc));
-            for (TimeZoneMapping timeZoneId : country.timeZoneIds) {
-                TimeZoneMapping.writeXml(timeZoneId, writer);
+            for (TimeZoneMapping timeZoneMapping : country.timeZoneMappings) {
+                TimeZoneMapping.writeXml(timeZoneMapping, writer);
             }
             writer.writeEndElement();
         }
@@ -212,24 +255,40 @@
         private final String olsonId;
         private final boolean showInPicker;
         private final Instant notUsedAfterInclusive;
+        private final String notAfterReplacementId;
+        private final List<String> alternativeZoneIds;
 
-        TimeZoneMapping(String olsonId, boolean showInPicker, Instant notUsedAfterInclusive) {
-            this.olsonId = olsonId;
+        TimeZoneMapping(String olsonId, boolean showInPicker, Instant notUsedAfterInclusive,
+                String notAfterReplacementId, List<String> alternativeZoneIds) {
+            this.olsonId = Objects.requireNonNull(olsonId);
             this.showInPicker = showInPicker;
+            if ((notUsedAfterInclusive == null) != (notAfterReplacementId == null)) {
+                throw new IllegalArgumentException(
+                        "Supply both notUsedAfterInclusive and notAfterReplacementId or neither");
+            }
             this.notUsedAfterInclusive = notUsedAfterInclusive;
+            this.notAfterReplacementId = notAfterReplacementId;
+            this.alternativeZoneIds = Objects.requireNonNull(alternativeZoneIds);
         }
 
-        static void writeXml(TimeZoneMapping timeZoneId, XMLStreamWriter writer)
+        static void writeXml(TimeZoneMapping timeZoneMapping, XMLStreamWriter writer)
                 throws XMLStreamException {
             writer.writeStartElement(ZONE_ID_ELEMENT);
-            if (!timeZoneId.showInPicker) {
+            if (!timeZoneMapping.showInPicker) {
                 writer.writeAttribute(ZONE_SHOW_IN_PICKER_ATTRIBUTE, encodeBooleanAttribute(false));
             }
-            if (timeZoneId.notUsedAfterInclusive != null) {
+            if (timeZoneMapping.notUsedAfterInclusive != null) {
                 writer.writeAttribute(ZONE_NOT_USED_AFTER_ATTRIBUTE,
-                        encodeLongAttribute(timeZoneId.notUsedAfterInclusive.toEpochMilli()));
+                        encodeLongAttribute(timeZoneMapping.notUsedAfterInclusive.toEpochMilli()));
+                writer.writeAttribute(ZONE_NOT_USED_REPLACEMENT_ID_ATTRIBUTE,
+                        timeZoneMapping.notAfterReplacementId);
             }
-            writer.writeCharacters(timeZoneId.olsonId);
+            if (!timeZoneMapping.alternativeZoneIds.isEmpty()) {
+                String alternativeZoneIdsString =
+                        String.join(",", timeZoneMapping.alternativeZoneIds);
+                writer.writeAttribute(ZONE_ALTERNATIVE_IDS_ATTRIBUTE, alternativeZoneIdsString);
+            }
+            writer.writeCharacters(timeZoneMapping.olsonId);
             writer.writeEndElement();
         }
     }
diff --git a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupGenerator.java b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupGenerator.java
index b6d368b..9bf86e0 100644
--- a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupGenerator.java
+++ b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupGenerator.java
@@ -15,33 +15,38 @@
  */
 package com.android.libcore.timezone.tzlookup;
 
-import com.android.libcore.timezone.tzlookup.proto.CountryZonesFile;
+import com.android.libcore.timezone.countryzones.proto.CountryZonesFile;
 import com.android.libcore.timezone.tzlookup.zonetree.CountryZoneTree;
 import com.android.libcore.timezone.tzlookup.zonetree.CountryZoneUsage;
 import com.android.libcore.timezone.util.Errors;
 import com.android.libcore.timezone.util.Errors.HaltExecutionException;
+import com.android.timezone.tzids.TimeZoneIds;
+import com.android.timezone.tzids.proto.TzIdsProto;
 import com.ibm.icu.util.BasicTimeZone;
 import com.ibm.icu.util.Calendar;
 import com.ibm.icu.util.GregorianCalendar;
 import com.ibm.icu.util.TimeZone;
 import com.ibm.icu.util.TimeZoneRule;
 
+import java.io.File;
 import java.io.IOException;
 import java.text.ParseException;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
+
 import javax.xml.stream.XMLStreamException;
 
 /**
- * Generates the tzlookup.xml file using the information from countryzones.txt and zones.tab.
- *
- * See {@link #main(String[])} for commandline information.
+ * Generates Android's tzlookup.xml and tzids.prototxt file using ICU4J, Android's countryzones.txt
+ * file, and TZDB's backwards and zones.tab files.
  */
 public final class TzLookupGenerator {
 
@@ -53,7 +58,7 @@
 
     /**
      * The end time (exclusive) for generating country zone usage. 20380119 03:14:07 UTC. Any times
-     * after this will be considered "infinity" for the "notAfter" value and not included. Chosen
+     * after this will be considered "infinity" for the "notafter" value and not included. Chosen
      * because this is a "nice round number" and has historical significance for people that deal
      * with computer time. There is no particular reason to choose this over another time; any
      * future time after the last time we expect the code to reasonably encounter will do.
@@ -70,32 +75,37 @@
     public static final Instant ZONE_USAGE_CALCS_END =
             ZONE_USAGE_NOT_AFTER_CUT_OFF.plus(2 * 365, ChronoUnit.DAYS);
 
-    private final String countryZonesFile;
-    private final String zoneTabFile;
-    private final String backwardFile;
-    private final String outputFile;
+    private final String countryZonesFileIn;
+    private final String zoneTabFileIn;
+    private final String backwardFileIn;
+    private final String tzLookupXmlFileOut;
+    private final String timeZoneIdsFileOut;
 
     /**
      * Executes the generator.
      */
     public static void main(String[] args) throws Exception {
-        if (args.length != 4) {
+        if (args.length != 5) {
             System.err.println(
                     "usage: java com.android.libcore.timezone.tzlookup.TzLookupGenerator"
-                            + " <input proto file> <zone.tab file> <backward file>"
-                            + " <output xml file>");
+                            + " <[in] countryzones.txt file> <[in] zone.tab file>"
+                            + " <[in] backward file>"
+                            + " <[out] tzlookup.xml file> <[out] zone IDs file>");
             System.exit(0);
         }
-        boolean success = new TzLookupGenerator(args[0], args[1], args[2], args[3]).execute();
+        TzLookupGenerator tzLookupGenerator =
+                new TzLookupGenerator(args[0], args[1], args[2], args[3], args[4]);
+        boolean success = tzLookupGenerator.execute();
         System.exit(success ? 0 : 1);
     }
 
-    TzLookupGenerator(String countryZonesFile, String zoneTabFile, String backwardFile,
-            String outputFile) {
-        this.countryZonesFile = countryZonesFile;
-        this.zoneTabFile = zoneTabFile;
-        this.backwardFile = backwardFile;
-        this.outputFile = outputFile;
+    TzLookupGenerator(String countryZonesFileIn, String zoneTabFileIn, String backwardFileIn,
+            String tzLookupXmlFileOut, String timeZoneIdsFileOut) {
+        this.countryZonesFileIn = countryZonesFileIn;
+        this.zoneTabFileIn = zoneTabFileIn;
+        this.backwardFileIn = backwardFileIn;
+        this.tzLookupXmlFileOut = tzLookupXmlFileOut;
+        this.timeZoneIdsFileOut = timeZoneIdsFileOut;
     }
 
     boolean execute() {
@@ -103,7 +113,7 @@
         try {
             // Parse the countryzones input file.
             CountryZonesFile.CountryZones countryZonesIn =
-                    parseAndValidateCountryZones(countryZonesFile, errors);
+                    parseAndValidateCountryZones(countryZonesFileIn, errors);
 
             // Check the countryzones.txt rules version matches the version that ICU is using.
             String icuTzDataVersion = TimeZone.getTZDataVersion();
@@ -113,21 +123,20 @@
                         + inputIanaVersion + " but the ICU you have is for " + icuTzDataVersion);
             }
 
-
             // Pull out information we want to validate against from zone.tab (which we have to
             // assume matches the ICU version since it doesn't contain its own version info).
-            Map<String, List<String>> zoneTabMapping = parseZoneTabFile(zoneTabFile, errors);
+            Map<String, List<String>> zoneTabMapping = parseZoneTabFile(zoneTabFileIn, errors);
 
             List<CountryZonesFile.Country> countriesIn = countryZonesIn.getCountriesList();
             List<String> countriesInIsos = CountryZonesFileSupport.extractIsoCodes(countriesIn);
 
-            // Sanity check the countryzones file only contains lower-case country codes. The output
-            // file uses them and the on-device code assumes lower case.
+            // Confidence check the countryzones file only contains lower-case country codes. The
+            // output file uses them and the on-device code assumes lower case.
             if (!Utils.allLowerCaseAscii(countriesInIsos)) {
                 throw errors.addFatalAndHalt(
                         "Non-lowercase country ISO codes found in: " + countriesInIsos);
             }
-            // Sanity check the countryzones file doesn't contain duplicate country entries.
+            // Confidence check the countryzones file doesn't contain duplicate country entries.
             if (!Utils.allUnique(countriesInIsos)) {
                 throw errors.addFatalAndHalt(
                         "Duplicate input country entries found: " + countriesInIsos);
@@ -139,31 +148,26 @@
             Set<String> timezonesCountryIsos = new HashSet<>(upperCaseCountriesInIsos);
             Set<String> zoneTabCountryIsos = zoneTabMapping.keySet();
             if (!zoneTabCountryIsos.equals(timezonesCountryIsos)) {
-                throw errors.addFatalAndHalt(zoneTabFile + " contains "
+                throw errors.addFatalAndHalt(zoneTabFileIn + " contains "
                         + Utils.subtract(zoneTabCountryIsos, timezonesCountryIsos)
                         + " not present in countryzones, "
-                        + countryZonesFile + " contains "
+                        + countryZonesFileIn + " contains "
                         + Utils.subtract(timezonesCountryIsos, zoneTabCountryIsos)
                         + " not present in zonetab.");
             }
 
             // Obtain and validate a mapping from old IDs to new IDs.
-            Map<String, String> zoneIdLinks = parseAndValidateBackwardFile(backwardFile, errors);
+            BackwardFile backwardIn = parseAndValidateBackwardFile(backwardFileIn, errors);
             errors.throwIfError("Errors accumulated");
 
-            TzLookupFile.TimeZones timeZonesOut = createOutputTimeZones(
-                    inputIanaVersion, zoneTabMapping, countriesIn, zoneIdLinks, errors);
-            errors.throwIfError("Errors accumulated");
+            OutputData outputData = createOutputData(
+                    inputIanaVersion, zoneTabMapping, countriesIn, backwardIn, errors);
 
             // Write the output structure if there wasn't an error.
-            logInfo("Writing " + outputFile);
-            try {
-                TzLookupFile.write(timeZonesOut, outputFile);
-            } catch (XMLStreamException e) {
-                throw errors.addFatalAndHalt("Unable to write output file", e);
-            }
+            errors.throwIfError("Errors accumulated");
+            writeOutputData(outputData, tzLookupXmlFileOut, timeZoneIdsFileOut, errors);
             return true;
-        } catch (HaltExecutionException | IOException e) {
+        } catch (HaltExecutionException e) {
             logError("Stopping due to fatal condition", e);
             return false;
         } finally {
@@ -192,14 +196,13 @@
      * Load the backward file and return the links contained within. This is used as the source of
      * equivalent time zone IDs.
      */
-    private static Map<String, String> parseAndValidateBackwardFile(
-            String backwardFile, Errors errors) {
+    private static BackwardFile parseAndValidateBackwardFile(String backwardFile, Errors errors) {
         errors.pushScope("Parsing " + backwardFile);
         try {
-            BackwardFile backwardIn = BackwardFile.parse(backwardFile);
+            BackwardFile backward = BackwardFile.parse(backwardFile);
 
             // Validate the links.
-            Map<String, String> zoneIdLinks = backwardIn.getDirectLinks();
+            Map<String, String> zoneIdLinks = backward.getLinks();
             zoneIdLinks.forEach(
                     (k, v) -> {
                         if (invalidTimeZoneId(k)) {
@@ -209,7 +212,7 @@
                             errors.addError("Bad 'to' link: " + k + "->" + v);
                         }
                     });
-            return zoneIdLinks;
+            return backward;
         } catch (ParseException | IOException e) {
             errors.addError("Unable to parse " + backwardFile, e);
             return null;
@@ -232,15 +235,44 @@
         }
     }
 
-    private static TzLookupFile.TimeZones createOutputTimeZones(String inputIanaVersion,
-            Map<String, List<String>> zoneTabMapping, List<CountryZonesFile.Country> countriesIn,
-            Map<String, String> zoneIdLinks, Errors errors)
+    private static void writeOutputData(OutputData outputData,
+            String tzLookupXmlFileName, String timeZoneIdsFileName, Errors errors)
             throws HaltExecutionException {
+        errors.pushScope("write " + tzLookupXmlFileName);
+        try {
+            // Write out the file used on device.
+            logInfo("Writing " + tzLookupXmlFileName);
+
+            TzLookupFile.TimeZones timeZonesOut = outputData.getTzLookupTimeZones();
+            TzLookupFile.write(timeZonesOut, tzLookupXmlFileName);
+        } catch (IOException | XMLStreamException e) {
+            errors.addFatalAndHalt("Unable to write " + tzLookupXmlFileName, e);
+        } finally {
+            errors.popScope();
+        }
+
+        errors.pushScope("write " + timeZoneIdsFileName);
+        try {
+            // Write out the tz IDs file used during later stages of the pipeline.
+            logInfo("Writing " + timeZoneIdsFileName);
+
+            TimeZoneIds timeZoneIds = outputData.getTimeZoneIds();
+            timeZoneIds.store(new File(timeZoneIdsFileName));
+        } catch (IOException e) {
+            errors.addFatalAndHalt("Unable to write " + timeZoneIdsFileName, e);
+        } finally {
+            errors.popScope();
+        }
+    }
+
+    private static OutputData createOutputData(String inputIanaVersion,
+            Map<String, List<String>> zoneTabMapping, List<CountryZonesFile.Country> countriesIn,
+            BackwardFile backwardIn, Errors errors) throws HaltExecutionException {
 
         // Start constructing the output structure.
         TzLookupFile.TimeZones timeZonesOut = new TzLookupFile.TimeZones(inputIanaVersion);
-        TzLookupFile.CountryZones countryZonesOut = new TzLookupFile.CountryZones();
-        timeZonesOut.setCountryZones(countryZonesOut);
+        TzLookupFile.CountryZones tzLookupCountryZones = new TzLookupFile.CountryZones();
+        timeZonesOut.setCountryZones(tzLookupCountryZones);
 
         // The time use when sampling the offsets for a zone.
         final long offsetSampleTimeMillis = getSampleOffsetTimeMillisForData(inputIanaVersion);
@@ -250,6 +282,9 @@
         // to WW2) so we start looking at the beginning of "this year".
         long everUseUtcStartTimeMillis = getYearStartTimeMillisForData(inputIanaVersion);
 
+        TzIdsProto.TimeZoneIds.Builder tzIdsBuilder = TzIdsProto.TimeZoneIds.newBuilder()
+                .setIanaVersion(inputIanaVersion);
+
         // Process each Country.
         for (CountryZonesFile.Country countryIn : countriesIn) {
             String isoCode = countryIn.getIsoCode();
@@ -260,22 +295,25 @@
                 continue;
             }
 
-            TzLookupFile.Country countryOut = processCountry(
+            CountryOutputData countryOutputData = processCountry(
                     offsetSampleTimeMillis, everUseUtcStartTimeMillis, countryIn,
-                    zoneTabCountryTimeZoneIds, zoneIdLinks, errors);
-            if (countryOut == null) {
+                    zoneTabCountryTimeZoneIds, backwardIn, errors);
+            if (countryOutputData == null) {
                 // Continue processing countries if there are only errors.
                 continue;
             }
-            countryZonesOut.addCountry(countryOut);
+
+            tzLookupCountryZones.addCountry(countryOutputData.getTzLookupCountry());
+            tzIdsBuilder.addCountryMappings(countryOutputData.getTimeZoneIdsCountryMapping());
         }
         errors.throwIfError("One or more countries failed");
-        return timeZonesOut;
+        TimeZoneIds timeZoneIds = new TimeZoneIds(tzIdsBuilder.build());
+        return new OutputData(timeZonesOut, timeZoneIds);
     }
 
-    private static TzLookupFile.Country processCountry(long offsetSampleTimeMillis,
+    private static CountryOutputData processCountry(long offsetSampleTimeMillis,
             long everUseUtcStartTimeMillis, CountryZonesFile.Country countryIn,
-            List<String> zoneTabCountryTimeZoneIds, Map<String, String> zoneIdLinks,
+            List<String> zoneTabCountryTimeZoneIds, BackwardFile backwardIn,
             Errors errors) {
         String isoCode = countryIn.getIsoCode();
         errors.pushScope("country=" + isoCode);
@@ -349,7 +387,7 @@
                 // the countryzones.txt needs to be updated with new IDs (or an alias can be added
                 // if there's some reason to keep using the old ID).
                 validateCountryZonesTzIdsAgainstIana(isoCode, zoneTabCountryTimeZoneIds,
-                        timeZonesIn, zoneIdLinks, errors);
+                        timeZonesIn, backwardIn.getDirectLinks(), errors);
                 if (errors.hasError()) {
                     // No point in continuing.
                     return null;
@@ -365,7 +403,7 @@
                 return null;
             }
 
-            // Add the country to the output structure.
+            // Create the tzlookup country structure.
             TzLookupFile.Country countryOut = new TzLookupFile.Country(
                     isoCode, defaultTimeZoneId, defaultTimeZoneBoost, everUsesUtc);
 
@@ -375,10 +413,18 @@
                         "id=" + timeZoneIn.getId() + ", offset=" + timeZoneIn.getUtcOffset()
                                 + ", shownInPicker=" + timeZoneIn.getShownInPicker());
                 try {
+                    String timeZoneInId = timeZoneIn.getId();
+
+                    // The notUsedAfterInstant can be null if the zone is used until at least
+                    // ZONE_CALCS_END_INSTANT. That's what we want.
+                    Instant notUsedAfterInstant =
+                            countryZoneUsage.getNotUsedAfterInstant(timeZoneInId);
+                    String notUsedReplacementId =
+                            countryZoneUsage.getNotUsedReplacementId(timeZoneInId);
+
                     // Validate the offset information in countryIn.
                     validateNonDstOffset(offsetSampleTimeMillis, countryIn, timeZoneIn, errors);
 
-                    String timeZoneInId = timeZoneIn.getId();
                     boolean shownInPicker = timeZoneIn.getShownInPicker();
                     if (!countryZoneUsage.hasEntry(timeZoneInId)) {
                         // This implies a programming error.
@@ -386,21 +432,27 @@
                         return null;
                     }
 
-                    // The notUsedAfterInstant can be null if the zone is used until at least
-                    // ZONE_CALCS_END_INSTANT. That's what we want.
-                    Instant notUsedAfterInstant =
-                            countryZoneUsage.getNotUsedAfterInstant(timeZoneInId);
+                    // Find all the alternative zone IDs for the chosen zone ID.
+                    List<String> alternativeZoneIds =
+                            new ArrayList<>(backwardIn.getAllAlternativeIds(timeZoneInId));
+                    Collections.sort(alternativeZoneIds);
 
                     // Add the id mapping and associated metadata.
-                    TzLookupFile.TimeZoneMapping timeZoneIdOut =
-                            new TzLookupFile.TimeZoneMapping(
-                                    timeZoneInId, shownInPicker, notUsedAfterInstant);
-                    countryOut.addTimeZoneIdentifier(timeZoneIdOut);
+                    TzLookupFile.TimeZoneMapping timeZoneIdOut = new TzLookupFile.TimeZoneMapping(
+                            timeZoneInId, shownInPicker, notUsedAfterInstant, notUsedReplacementId,
+                            alternativeZoneIds);
+                    countryOut.addTimeZoneMapping(timeZoneIdOut);
                 } finally {
                     errors.popScope();
                 }
             }
-            return countryOut;
+
+            // CountryMapping contains only information that is available from Country so we can
+            // currently build one from the other.
+            TzIdsProto.CountryMapping countryMappingProto =
+                    TzLookupFile.Country.createCountryMappingProto(countryOut);
+
+            return new CountryOutputData(countryOut, countryMappingProto);
         } finally{
             // End of country processing.
             errors.popScope();
@@ -604,4 +656,42 @@
     private static void logInfo(String msg) {
         System.err.println("I: " + msg);
     }
+
+    private static class CountryOutputData {
+        private final TzLookupFile.Country tzLookupCountry;
+        private final TzIdsProto.CountryMapping timeZoneIdsCountryMapping;
+
+        private CountryOutputData(TzLookupFile.Country tzLookupCountry,
+                TzIdsProto.CountryMapping timeZoneIdsCountryMapping) {
+            this.tzLookupCountry = Objects.requireNonNull(tzLookupCountry);
+            this.timeZoneIdsCountryMapping = Objects.requireNonNull(timeZoneIdsCountryMapping);
+        }
+
+        private TzLookupFile.Country getTzLookupCountry() {
+            return tzLookupCountry;
+        }
+
+        private TzIdsProto.CountryMapping getTimeZoneIdsCountryMapping() {
+            return timeZoneIdsCountryMapping;
+        }
+    }
+
+    private static class OutputData {
+
+        private final TzLookupFile.TimeZones tzLookupTimeZones;
+        private final TimeZoneIds timeZoneIds;
+
+        private OutputData(TzLookupFile.TimeZones tzLookupTimeZones, TimeZoneIds timeZoneIds) {
+            this.tzLookupTimeZones = Objects.requireNonNull(tzLookupTimeZones);
+            this.timeZoneIds = Objects.requireNonNull(timeZoneIds);
+        }
+
+        private TzLookupFile.TimeZones getTzLookupTimeZones() {
+            return tzLookupTimeZones;
+        }
+
+        private TimeZoneIds getTimeZoneIds() {
+            return timeZoneIds;
+        }
+    }
 }
diff --git a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneTree.java b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneTree.java
index 23c2b0a..88c9f21 100644
--- a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneTree.java
+++ b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneTree.java
@@ -15,8 +15,8 @@
  */
 package com.android.libcore.timezone.tzlookup.zonetree;
 
-import com.android.libcore.timezone.tzlookup.proto.CountryZonesFile;
-import com.android.libcore.timezone.tzlookup.proto.CountryZonesFile.Country;
+import com.android.libcore.timezone.countryzones.proto.CountryZonesFile;
+import com.android.libcore.timezone.countryzones.proto.CountryZonesFile.Country;
 import com.android.libcore.timezone.tzlookup.zonetree.ZoneOffsetPeriod.ZonePeriodsKey;
 import com.ibm.icu.text.TimeZoneNames;
 import com.ibm.icu.util.BasicTimeZone;
@@ -510,27 +510,44 @@
                 }
 
                 Instant endInstant = node.getEndInstant();
+                String replacementTimeZoneId = findReplacementTimeZoneId(node);
                 if (!node.isLeaf()) {
                     ZoneInfo primaryZone = node.getPrimaryZoneInfo();
-                    addZoneEntryIfMissing(endInstant, primaryZone);
+                    addZoneEntryIfMissing(endInstant, replacementTimeZoneId, primaryZone);
                 } else {
                     // In some rare cases (e.g. Canada: Swift_Current and Creston) zones have agreed
                     // completely since 1970 so some leaves may have multiple zones. So, attempt to
                     // add all zones for leaves, not just the primary.
                     for (ZoneInfo zoneInfo : node.getZoneInfos()) {
-                        addZoneEntryIfMissing(endInstant, zoneInfo);
+                        addZoneEntryIfMissing(endInstant, replacementTimeZoneId, zoneInfo);
                     }
                 }
             }
 
-            private void addZoneEntryIfMissing(Instant endInstant, ZoneInfo zoneInfo) {
+            /**
+             * Find the time zone that the node ultimately "merges" into, i.e. the one it is
+             * effectively replaced by.
+             */
+            private String findReplacementTimeZoneId(ZoneNode node) {
+                if (node.getParent().isRoot()) {
+                    return null;
+                }
+                do {
+                    node = node.getParent();
+                } while (!node.getParent().isRoot());
+                return node.primaryZoneInfo.getZoneId();
+            }
+
+            private void addZoneEntryIfMissing(
+                    Instant endInstant, String replacementTimeZoneId, ZoneInfo zoneInfo) {
                 String zoneId = zoneInfo.getZoneId();
                 if (!notAfterCutOff.isAfter(endInstant)) {
                     // notAfterCutOff <= endInstant
                     endInstant = null;
+                    replacementTimeZoneId = null;
                 }
                 if (!zoneUsage.hasEntry(zoneId)) {
-                    zoneUsage.addEntry(zoneId, endInstant);
+                    zoneUsage.addEntry(zoneId, endInstant, replacementTimeZoneId);
                 }
             }
 
diff --git a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneUsage.java b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneUsage.java
index 813d741..334c66b 100644
--- a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneUsage.java
+++ b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneUsage.java
@@ -18,6 +18,7 @@
 import java.time.Instant;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * A record for a country of when zones stopped being (effectively) used.
@@ -34,12 +35,12 @@
         return isoCode;
     }
 
-    void addEntry(String zoneId, Instant notUsedAfterInstant) {
+    void addEntry(String zoneId, Instant notUsedAfterInstant, String notUsedReplacementId) {
         if (zoneIdEntryMap.containsKey(zoneId)) {
             throw new IllegalArgumentException(
                     "Entry exists for " + zoneId + " for isoCode=" + isoCode);
         }
-        zoneIdEntryMap.put(zoneId, new Entry(zoneId, notUsedAfterInstant));
+        zoneIdEntryMap.put(zoneId, new Entry(zoneId, notUsedAfterInstant, notUsedReplacementId));
     }
 
     public boolean hasEntry(String zoneId) {
@@ -50,18 +51,34 @@
         Entry entry = zoneIdEntryMap.get(zoneId);
         if (entry == null) {
             throw new IllegalArgumentException(
-                    "No entry for " + zoneId+ " for isoCode=" + isoCode);
+                    "No entry for " + zoneId + " for isoCode=" + isoCode);
         }
         return entry.notUsedAfter;
     }
 
+    public String getNotUsedReplacementId(String zoneId) {
+        Entry entry = zoneIdEntryMap.get(zoneId);
+        if (entry == null) {
+            throw new IllegalArgumentException(
+                    "No entry for " + zoneId + " for isoCode=" + isoCode);
+        }
+        return entry.notUsedReplacementId;
+    }
+
     private static class Entry {
         final String zoneId;
         final Instant notUsedAfter;
+        final String notUsedReplacementId;
 
-        Entry(String zoneId, Instant notUsedAfter) {
-            this.zoneId = zoneId;
+        Entry(String zoneId, Instant notUsedAfter, String notUsedReplacementId) {
+            this.zoneId = Objects.requireNonNull(zoneId);
+
+            if ((notUsedAfter == null) != (notUsedReplacementId == null)) {
+                throw new IllegalArgumentException(
+                        "Both notUsedAfter and notUsedReplacement, or neither required");
+            }
             this.notUsedAfter = notUsedAfter;
+            this.notUsedReplacementId = notUsedReplacementId;
         }
     }
 }
diff --git a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/UniqueZonesVisualizer.java b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/UniqueZonesVisualizer.java
index 8d6f6c7..258872f 100644
--- a/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/UniqueZonesVisualizer.java
+++ b/input_tools/android/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/zonetree/UniqueZonesVisualizer.java
@@ -15,10 +15,10 @@
  */
 package com.android.libcore.timezone.tzlookup.zonetree;
 
+import com.android.libcore.timezone.countryzones.proto.CountryZonesFile.Country;
+import com.android.libcore.timezone.countryzones.proto.CountryZonesFile.CountryZones;
 import com.android.libcore.timezone.tzlookup.CountryZonesFileSupport;
 import com.android.libcore.timezone.tzlookup.TzLookupGenerator;
-import com.android.libcore.timezone.tzlookup.proto.CountryZonesFile.Country;
-import com.android.libcore.timezone.tzlookup.proto.CountryZonesFile.CountryZones;
 
 import java.io.IOException;
 import java.time.Instant;
diff --git a/input_tools/android/tzlookup_generator/src/main/proto/country_zones_file.proto b/input_tools/android/tzlookup_generator/src/main/proto/country_zones_file.proto
index 9ed5644..de3085b 100644
--- a/input_tools/android/tzlookup_generator/src/main/proto/country_zones_file.proto
+++ b/input_tools/android/tzlookup_generator/src/main/proto/country_zones_file.proto
@@ -16,10 +16,10 @@
 
 syntax = "proto2";
 
-option java_package = "com.android.libcore.timezone.tzlookup.proto";
+option java_package = "com.android.libcore.timezone.countryzones.proto";
 option java_multiple_files = false;
 
-package com.android.libcore.timezone.tzlookup.proto;
+package com.android.libcore.timezone.countryzones.proto;
 
 message CountryZones {
     required string ianaVersion = 1;
diff --git a/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/BackwardFileTest.java b/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/BackwardFileTest.java
index c575a8e..bed94e5 100644
--- a/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/BackwardFileTest.java
+++ b/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/BackwardFileTest.java
@@ -30,8 +30,11 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.text.ParseException;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 public class BackwardFileTest {
 
@@ -78,19 +81,34 @@
                 "Link\tAfrica/Nairobi\t\tAfrica/Asmera",
                 "# This is a comment",
                 "Link\tAfrica/Abidjan\t\tAfrica/Timbuktu",
-                "# This is a comment"
+                "# This is a comment",
+                "Link\tAfrica/Timbuktu\t\tAfrica/Timbuktu2"
         );
         BackwardFile backward = BackwardFile.parse(file);
         Map<String, String> expectedLinks = new HashMap<>();
         expectedLinks.put("America/Godthab", "America/Nuuk");
         expectedLinks.put("Africa/Asmera", "Africa/Nairobi");
         expectedLinks.put("Africa/Timbuktu", "Africa/Abidjan");
+        expectedLinks.put("Africa/Timbuktu2", "Africa/Timbuktu");
+        assertEquals(expectedLinks, backward.getLinks());
 
-        assertEquals(expectedLinks, backward.getDirectLinks());
+        Map<String, String> expectedDirectLinks = new HashMap<>();
+        expectedDirectLinks.put("America/Godthab", "America/Nuuk");
+        expectedDirectLinks.put("Africa/Asmera", "Africa/Nairobi");
+        expectedDirectLinks.put("Africa/Timbuktu", "Africa/Abidjan");
+        expectedDirectLinks.put("Africa/Timbuktu2", "Africa/Abidjan");
+        assertEquals(expectedDirectLinks, backward.getDirectLinks());
+
+        assertEquals(set("Africa/Abidjan", "Africa/Timbuktu2"),
+                backward.getAllAlternativeIds("Africa/Timbuktu"));
+        assertEquals(set("Africa/Abidjan", "Africa/Timbuktu"),
+                backward.getAllAlternativeIds("Africa/Timbuktu2"));
+        assertEquals(set("Africa/Timbuktu", "Africa/Timbuktu2"),
+                backward.getAllAlternativeIds("Africa/Abidjan"));
     }
 
     @Test(expected = IllegalStateException.class)
-    public void getLinksWithLoop() throws Exception {
+    public void getDirectLinksWithLoop() throws Exception {
         String file = createFile(
                 "Link\tAmerica/New_York\t\tAmerica/Los_Angeles",
                 "Link\tAmerica/Los_Angeles\t\tAmerica/Phoenix",
@@ -119,4 +137,8 @@
     private String createFile(String... lines) throws IOException {
         return TestUtils.createFile(tempDir, lines);
     }
+
+    private static <T> Set<T> set(T... values) {
+        return new HashSet<>(Arrays.asList(values));
+    }
 }
diff --git a/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/TzLookupGeneratorTest.java b/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/TzLookupGeneratorTest.java
index d8677cc..a3d4976 100644
--- a/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/TzLookupGeneratorTest.java
+++ b/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/TzLookupGeneratorTest.java
@@ -16,8 +16,17 @@
 
 package com.android.libcore.timezone.tzlookup;
 
+import static com.android.libcore.timezone.countryzones.proto.CountryZonesFile.Country;
+import static com.android.libcore.timezone.testing.TestUtils.assertAbsent;
+import static com.android.libcore.timezone.testing.TestUtils.assertContains;
+import static com.android.libcore.timezone.testing.TestUtils.createFile;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.libcore.timezone.countryzones.proto.CountryZonesFile;
 import com.android.libcore.timezone.testing.TestUtils;
-import com.android.libcore.timezone.tzlookup.proto.CountryZonesFile;
+import com.android.timezone.tzids.proto.TzIdsProto;
 import com.google.protobuf.TextFormat;
 import com.ibm.icu.util.TimeZone;
 
@@ -37,17 +46,10 @@
 import java.util.Map;
 import java.util.stream.Collectors;
 
-import static com.android.libcore.timezone.testing.TestUtils.assertAbsent;
-import static com.android.libcore.timezone.testing.TestUtils.assertContains;
-import static com.android.libcore.timezone.testing.TestUtils.createFile;
-import static com.android.libcore.timezone.tzlookup.proto.CountryZonesFile.Country;
-import static junit.framework.TestCase.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
 public class TzLookupGeneratorTest {
 
-    public static final String INVALID_TIME_ZONE_ID = "NOT_A_VALID_ID";
+    private static final String INVALID_TIME_ZONE_ID = "NOT_A_VALID_ID";
+    private static final String TZDB_VERSION = TimeZone.getTZDataVersion();
 
     private Path tempDir;
 
@@ -66,11 +68,12 @@
         String countryZonesFile = createFile(tempDir, "THIS IS NOT A VALID FILE");
         List<ZoneTabFile.CountryEntry> gbZoneTabEntries = createValidZoneTabEntriesGb();
         String zoneTabFile = createZoneTabFile(gbZoneTabEntries);
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
     }
 
@@ -85,16 +88,17 @@
 
         List<ZoneTabFile.CountryEntry> gbZoneTabEntries = createValidZoneTabEntriesGb();
         String zoneTabFile = createZoneTabFile(gbZoneTabEntries);
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -104,18 +108,19 @@
                 createValidCountryGb().toBuilder().clearTimeZoneMappings().build();
         CountryZonesFile.CountryZones countryZones = createValidCountryZones(gbWithoutZones);
         String countryZonesFile = createCountryZonesFile(countryZones);
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
 
         String zoneTabFile = createZoneTabFile(createValidZoneTabEntriesGb());
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -130,18 +135,19 @@
         CountryZonesFile.CountryZones countryZones =
                 createValidCountryZones(gbWithDuplicateZones);
         String countryZonesFile = createCountryZonesFile(countryZones);
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
 
         String zoneTabFile = createZoneTabFile(createValidZoneTabEntriesGb());
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -156,16 +162,17 @@
 
         List<ZoneTabFile.CountryEntry> gbZoneTabEntries = createValidZoneTabEntriesGb();
         String zoneTabFile = createZoneTabFile(gbZoneTabEntries);
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -179,16 +186,17 @@
 
         List<ZoneTabFile.CountryEntry> gbZoneTabEntries = createValidZoneTabEntriesGb();
         String zoneTabFile = createZoneTabFile(gbZoneTabEntries);
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -202,11 +210,11 @@
                 .clearDefaultTimeZoneId().build();
         List<ZoneTabFile.CountryEntry> gbZoneTabEntries = createValidZoneTabEntriesGb();
 
-        String tzLookupXml = generateTzLookupXml(gbWithoutDefault, gbZoneTabEntries,
-                createValidBackwardLinks());
+        OutputData outputData =
+                generateOutputData(gbWithoutDefault, gbZoneTabEntries, createEmptyBackwardLinks());
 
         // Check gb's time zone was defaulted.
-        assertContains(tzLookupXml, "code=\"gb\" default=\"" + gbTimeZoneId + "\"");
+        assertContains(outputData.tzLookupXml, "code=\"gb\" default=\"" + gbTimeZoneId + "\"");
     }
 
     @Test
@@ -220,11 +228,11 @@
                         .build();
         List<ZoneTabFile.CountryEntry> gbZoneTabEntries = createValidZoneTabEntriesGb();
 
-        String tzLookupXml = generateTzLookupXml(gbWithExplicitDefaultTimeZone, gbZoneTabEntries,
-                createValidBackwardLinks());
+        OutputData outputData = generateOutputData(
+                gbWithExplicitDefaultTimeZone, gbZoneTabEntries, createEmptyBackwardLinks());
 
         // Check gb's time zone was defaulted.
-        assertContains(tzLookupXml, "code=\"gb\" default=\"" + gbTimeZoneId + "\"");
+        assertContains(outputData.tzLookupXml, "code=\"gb\" default=\"" + gbTimeZoneId + "\"");
     }
 
     @Test
@@ -239,16 +247,17 @@
 
         List<ZoneTabFile.CountryEntry> gbZoneTabEntries = createValidZoneTabEntriesGb();
         String zoneTabFile = createZoneTabFile(gbZoneTabEntries);
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -262,16 +271,17 @@
 
         List<ZoneTabFile.CountryEntry> gbZoneTabEntries = createValidZoneTabEntriesGb();
         String zoneTabFile = createZoneTabFile(gbZoneTabEntries);
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -283,15 +293,16 @@
 
         String zoneTabFile =
                 createZoneTabFile(createValidZoneTabEntriesFr(), createValidZoneTabEntriesUs());
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -305,15 +316,16 @@
         String countryZonesFile = createCountryZonesFile(countryZones);
 
         String zoneTabFile = createZoneTabFile(createValidZoneTabEntriesGb());
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -325,15 +337,16 @@
         String zoneTabFileWithDupes = createZoneTabFile(
                 createValidZoneTabEntriesGb(), createValidZoneTabEntriesGb());
 
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
         TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
-                countryZonesFile, zoneTabFileWithDupes, backwardFile, outputFile);
+                countryZonesFile, zoneTabFileWithDupes, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -347,16 +360,17 @@
         String countryZonesFile = createCountryZonesFile(countryZones);
 
         String zoneTabFile = createZoneTabFile(createValidZoneTabEntriesGb());
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -374,16 +388,17 @@
                 new ArrayList<>(createValidZoneTabEntriesGb());
         zoneTabEntriesWithBadId.add(new ZoneTabFile.CountryEntry("GB", INVALID_TIME_ZONE_ID));
         String zoneTabFile = createZoneTabFile(zoneTabEntriesWithBadId);
-        String backwardFile = createBackwardFile(createValidBackwardLinks());
+        String backwardFile = createBackwardFile(createEmptyBackwardLinks());
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
@@ -394,20 +409,55 @@
 
         String badBackwardFile = TestUtils.createFile(tempDir, "THIS IS NOT VALID");
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, badBackwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, badBackwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertEquals(0, Files.size(outputFilePath));
+        assertFileMissing(tzLookupFile);
+        assertFileMissing(tzIdsFile);
     }
 
     @Test
-    public void usingOldLinksValid() throws Exception {
+    public void checkNormalLinks() throws Exception {
+        String countryZonesText = "isoCode:\"gb\"\n"
+                + "timeZoneMappings:<\n"
+                + "  utcOffset:\"0:00\"\n"
+                + "  id:\"Europe/London\"\n"
+                + ">\n";
+
+        Country country = parseCountry(countryZonesText);
+        List<ZoneTabFile.CountryEntry> zoneTab = Arrays.asList(
+                new ZoneTabFile.CountryEntry("GB", "Europe/London"));
+        Map<String, String> backwardLinks = new HashMap<>();
+        // GB is an obsoleted ID for Europe/London.
+        backwardLinks.put("GB", "Europe/London");
+
+        OutputData outputData = generateOutputData(country, zoneTab, backwardLinks);
+
+        // GB will be listed as an alternative for Europe/London.
+        String expectedTzLookupXmlLine = "<id alts=\"GB\">Europe/London</id>\n";
+        assertContains(outputData.tzLookupXml, expectedTzLookupXmlLine);
+
+        TzIdsProto.TimeZoneIds.Builder tzIdsBuilder = TzIdsProto.TimeZoneIds
+                .newBuilder()
+                .setIanaVersion(TZDB_VERSION);
+        TzIdsProto.CountryMapping.Builder b = TzIdsProto.CountryMapping.newBuilder()
+                .setIsoCode("gb")
+                .addTimeZoneIds("Europe/London");
+        addLink(b, "GB" /* alternativeId */, "Europe/London" /* preferredId */);
+        tzIdsBuilder.addCountryMappings(b);
+        assertEquals(tzIdsBuilder.build(), outputData.timeZoneIds);
+    }
+
+    @Test
+    public void usingOldIdsInCountryTextIsValid() throws Exception {
         // This simulates a case where America/Godthab has been superseded by America/Nuuk in IANA
-        // data, but Android wants to continue using America/Godthab.
+        // data, but Android wants to continue using America/Godthab. This is signaled as deliberate
+        // through the use of the aliasId in countryzones.txt (otherwise the tooling will complain,
+        // see next test).
         String countryZonesWithOldIdText =
                 "isoCode:\"gl\"\n"
                 + "defaultTimeZoneId:\"America/Godthab\"\n"
@@ -438,20 +488,47 @@
                 new ZoneTabFile.CountryEntry("GL", "America/Scoresbysund"),
                 new ZoneTabFile.CountryEntry("GL", "America/Thule")
         );
-        Map<String, String> links = new HashMap<>();
-        links.put("America/Godthab", "America/Nuuk");
+        Map<String, String> backwardLinks = new HashMap<>();
+        backwardLinks.put("America/Godthab", "America/Nuuk");
 
-        String tzLookupXml = generateTzLookupXml(country, zoneTabWithNewIds, links);
+        OutputData outputData = generateOutputData(country, zoneTabWithNewIds, backwardLinks);
 
-        String expectedOutput =
-                "<id>America/Danmarkshavn</id>\n"
-                        + "<id>America/Scoresbysund</id>\n"
-                        + "<id>America/Godthab</id>\n"
-                        + "<id>America/Thule</id>\n";
-        String[] expectedLines = expectedOutput.split("\\n");
-        for (String expectedLine : expectedLines) {
-            assertContains(tzLookupXml, expectedLine);
+        String expectedTzLookupOutput = "<id>America/Danmarkshavn</id>\n"
+                + "<id>America/Scoresbysund</id>\n"
+                + "<id alts=\"America/Nuuk\">America/Godthab</id>\n"
+                + "<id>America/Thule</id>\n";
+        String[] expectedTzLookupXmlLines = expectedTzLookupOutput.split("\\n");
+        for (String expectedTzLookupXmlLine : expectedTzLookupXmlLines) {
+            assertContains(outputData.tzLookupXml, expectedTzLookupXmlLine);
         }
+
+        TzIdsProto.TimeZoneIds.Builder tzIdsBuilder = TzIdsProto.TimeZoneIds
+                .newBuilder()
+                .setIanaVersion(TZDB_VERSION);
+
+        TzIdsProto.CountryMapping.Builder b = TzIdsProto.CountryMapping.newBuilder()
+                .setIsoCode("gl")
+                .addTimeZoneIds("America/Danmarkshavn")
+                .addTimeZoneIds("America/Scoresbysund")
+                .addTimeZoneIds("America/Godthab")
+                .addTimeZoneIds("America/Thule");
+
+        // Because Android lists America/Nuuk as the aliasId in countryzones.txt, the link will
+        // be reversed from the usual.
+        addLink(b, "America/Nuuk" /* alternativeId */, "America/Godthab" /* preferredId */);
+
+        tzIdsBuilder.addCountryMappings(b);
+        assertEquals(tzIdsBuilder.build(), outputData.timeZoneIds);
+    }
+
+    private static void addLink(TzIdsProto.CountryMapping.Builder builder, String alternativeId,
+            String preferredId) {
+        TzIdsProto.TimeZoneLink link =
+                TzIdsProto.TimeZoneLink.newBuilder()
+                        .setAlternativeId(alternativeId)
+                        .setPreferredId(preferredId)
+                        .build();
+        builder.addTimeZoneLinks(link);
     }
 
     @Test
@@ -500,21 +577,21 @@
     @Test
     public void everUtc_true() throws Exception {
         CountryZonesFile.Country validCountryGb = createValidCountryGb();
-        String tzLookupXml = generateTzLookupXml(validCountryGb, createValidZoneTabEntriesGb(),
-                createValidBackwardLinks());
+        OutputData outputData = generateOutputData(
+                validCountryGb, createValidZoneTabEntriesGb(), createEmptyBackwardLinks());
 
         // Check gb's entry contains everutc="y".
-        assertContains(tzLookupXml, "everutc=\"y\"");
+        assertContains(outputData.tzLookupXml, "everutc=\"y\"");
     }
 
     @Test
     public void everUtc_false() throws Exception {
         CountryZonesFile.Country validCountryFr = createValidCountryFr();
-        String tzLookupXml = generateTzLookupXml(validCountryFr, createValidZoneTabEntriesFr(),
-                createValidBackwardLinks());
+        OutputData outputData = generateOutputData(
+                validCountryFr, createValidZoneTabEntriesFr(), createEmptyBackwardLinks());
 
         // Check fr's entry contains everutc="n".
-        assertContains(tzLookupXml, "everutc=\"n\"");
+        assertContains(outputData.tzLookupXml, "everutc=\"n\"");
     }
 
     @Test
@@ -529,10 +606,10 @@
         countryBuilder.setTimeZoneMappings(0, timeZoneMappingBuilder);
         CountryZonesFile.Country country = countryBuilder.build();
 
-        String tzLookupXml = generateTzLookupXml(country, createValidZoneTabEntriesFr(),
-                createValidBackwardLinks());
+        OutputData outputData = generateOutputData(
+                country, createValidZoneTabEntriesFr(), createEmptyBackwardLinks());
 
-        assertContains(tzLookupXml, "picker=\"n\"");
+        assertContains(outputData.tzLookupXml, "picker=\"n\"");
     }
 
     @Test
@@ -547,56 +624,117 @@
         countryBuilder.setTimeZoneMappings(0, timeZoneMappingBuilder);
         CountryZonesFile.Country country = countryBuilder.build();
 
-        String tzLookupXml = generateTzLookupXml(country, createValidZoneTabEntriesFr(),
-                createValidBackwardLinks());
+        OutputData outputData = generateOutputData(
+                country, createValidZoneTabEntriesFr(), createEmptyBackwardLinks());
 
         // We should not see anything "picker="y" is the implicit default.
-        assertAbsent(tzLookupXml, "picker=");
+        assertAbsent(outputData.tzLookupXml, "picker=");
     }
 
     @Test
     public void notAfter() throws Exception {
         CountryZonesFile.Country country = createValidCountryUs();
         List<ZoneTabFile.CountryEntry> zoneTabEntries = createValidZoneTabEntriesUs();
-        String tzLookupXml = generateTzLookupXml(country, zoneTabEntries,
-                createValidBackwardLinks());
-        String expectedOutput =
+        OutputData outputData = generateOutputData(
+                country, zoneTabEntries, createEmptyBackwardLinks());
+        String expectedTzLookupOutput =
                 "<id>America/New_York</id>\n"
-                + "<id notafter=\"167814000000\">America/Detroit</id>\n"
-                + "<id notafter=\"152089200000\">America/Kentucky/Louisville</id>\n"
-                + "<id notafter=\"972802800000\">America/Kentucky/Monticello</id>\n"
-                + "<id notafter=\"1130652000000\">America/Indiana/Indianapolis</id>\n"
-                + "<id notafter=\"1194159600000\">America/Indiana/Vincennes</id>\n"
-                + "<id notafter=\"1173600000000\">America/Indiana/Winamac</id>\n"
-                + "<id notafter=\"183535200000\">America/Indiana/Marengo</id>\n"
-                + "<id notafter=\"247042800000\">America/Indiana/Petersburg</id>\n"
-                + "<id notafter=\"89186400000\">America/Indiana/Vevay</id>\n"
+                + "<id notafter=\"167814000000\" repl=\"America/New_York\">America/Detroit</id>\n"
+                + "<id notafter=\"152089200000\" repl=\"America/New_York\">America/Kentucky/Louisville</id>\n"
+                + "<id notafter=\"972802800000\" repl=\"America/New_York\">America/Kentucky/Monticello</id>\n"
+                + "<id notafter=\"1130652000000\" repl=\"America/New_York\">America/Indiana/Indianapolis</id>\n"
+                + "<id notafter=\"1194159600000\" repl=\"America/New_York\">America/Indiana/Vincennes</id>\n"
+                + "<id notafter=\"1173600000000\" repl=\"America/New_York\">America/Indiana/Winamac</id>\n"
+                + "<id notafter=\"183535200000\" repl=\"America/New_York\">America/Indiana/Marengo</id>\n"
+                + "<id notafter=\"247042800000\" repl=\"America/New_York\">America/Indiana/Petersburg</id>\n"
+                + "<id notafter=\"89186400000\" repl=\"America/New_York\">America/Indiana/Vevay</id>\n"
                 + "<id>America/Chicago</id>\n"
-                + "<id notafter=\"688546800000\">America/Indiana/Knox</id>\n"
-                + "<id notafter=\"104918400000\">America/Menominee</id>\n"
-                + "<id notafter=\"720000000000\">America/North_Dakota/Center</id>\n"
-                + "<id notafter=\"1067155200000\">America/North_Dakota/New_Salem</id>\n"
-                + "<id notafter=\"1143964800000\">America/Indiana/Tell_City</id>\n"
-                + "<id notafter=\"1289116800000\">America/North_Dakota/Beulah</id>\n"
+                + "<id notafter=\"688546800000\" repl=\"America/Chicago\">America/Indiana/Knox</id>\n"
+                + "<id notafter=\"104918400000\" repl=\"America/Chicago\">America/Menominee</id>\n"
+                + "<id notafter=\"720000000000\" repl=\"America/Chicago\">America/North_Dakota/Center</id>\n"
+                + "<id notafter=\"1067155200000\" repl=\"America/Chicago\">America/North_Dakota/New_Salem</id>\n"
+                + "<id notafter=\"1143964800000\" repl=\"America/Chicago\">America/Indiana/Tell_City</id>\n"
+                + "<id notafter=\"1289116800000\" repl=\"America/Chicago\">America/North_Dakota/Beulah</id>\n"
                 + "<id>America/Denver</id>\n"
-                + "<id notafter=\"129114000000\">America/Boise</id>\n"
                 + "<id>America/Phoenix</id>\n"
+                + "<id notafter=\"129114000000\" repl=\"America/Phoenix\">America/Boise</id>\n"
                 + "<id>America/Los_Angeles</id>\n"
                 + "<id>America/Anchorage</id>\n"
-                + "<id notafter=\"436359600000\">America/Juneau</id>\n"
-                + "<id notafter=\"436356000000\">America/Yakutat</id>\n"
-                + "<id notafter=\"436363200000\">America/Nome</id>\n"
-                + "<id notafter=\"1547978400000\">America/Metlakatla</id>\n"
-                + "<id notafter=\"341402400000\">America/Sitka</id>\n"
+                + "<id notafter=\"436359600000\" repl=\"America/Anchorage\">America/Juneau</id>\n"
+                + "<id notafter=\"436356000000\" repl=\"America/Anchorage\">America/Yakutat</id>\n"
+                + "<id notafter=\"436363200000\" repl=\"America/Anchorage\">America/Nome</id>\n"
+                + "<id notafter=\"1547978400000\" repl=\"America/Anchorage\">America/Metlakatla</id>\n"
+                + "<id notafter=\"341402400000\" repl=\"America/Anchorage\">America/Sitka</id>\n"
                 + "<id>Pacific/Honolulu</id>\n"
                 + "<id>America/Adak</id>\n";
-        String[] expectedLines = expectedOutput.split("\\n");
-        for (String expectedLine : expectedLines) {
-            assertContains(tzLookupXml, expectedLine);
+        String[] expectedTzLookupXmlLines = expectedTzLookupOutput.split("\\n");
+        for (String expectedTzLookupXmlLine : expectedTzLookupXmlLines) {
+            assertContains(outputData.tzLookupXml, expectedTzLookupXmlLine);
+        }
+        
+        TzIdsProto.TimeZoneIds.Builder tzIdsBuilder = TzIdsProto.TimeZoneIds
+                .newBuilder()
+                .setIanaVersion(TZDB_VERSION);
+
+        TzIdsProto.CountryMapping.Builder b = TzIdsProto.CountryMapping.newBuilder()
+                .setIsoCode("us")
+                .addTimeZoneIds("America/New_York")
+                .addTimeZoneIds("America/Chicago")
+                .addTimeZoneIds("America/Denver")
+                .addTimeZoneIds("America/Phoenix")
+                .addTimeZoneIds("America/Los_Angeles")
+                .addTimeZoneIds("America/Anchorage")
+                .addTimeZoneIds("Pacific/Honolulu")
+                .addTimeZoneIds("America/Adak");
+
+        addReplacement(b, 167814000000L, "America/New_York", "America/Detroit");
+        addReplacement(b, 152089200000L, "America/New_York", "America/Kentucky/Louisville");
+        addReplacement(b, 972802800000L, "America/New_York", "America/Kentucky/Monticello");
+        addReplacement(b, 1130652000000L, "America/New_York", "America/Indiana/Indianapolis");
+        addReplacement(b, 1194159600000L, "America/New_York", "America/Indiana/Vincennes");
+        addReplacement(b, 1173600000000L, "America/New_York", "America/Indiana/Winamac");
+        addReplacement(b, 183535200000L, "America/New_York", "America/Indiana/Marengo");
+        addReplacement(b, 247042800000L, "America/New_York", "America/Indiana/Petersburg");
+        addReplacement(b, 89186400000L, "America/New_York", "America/Indiana/Vevay");
+        addReplacement(b, 688546800000L, "America/Chicago", "America/Indiana/Knox");
+        addReplacement(b, 104918400000L, "America/Chicago", "America/Menominee");
+        addReplacement(b, 720000000000L, "America/Chicago", "America/North_Dakota/Center");
+        addReplacement(b, 1067155200000L, "America/Chicago", "America/North_Dakota/New_Salem");
+        addReplacement(b, 1143964800000L, "America/Chicago", "America/Indiana/Tell_City");
+        addReplacement(b, 1289116800000L, "America/Chicago", "America/North_Dakota/Beulah");
+        addReplacement(b, 129114000000L, "America/Phoenix", "America/Boise");
+        addReplacement(b, 436359600000L, "America/Anchorage", "America/Juneau");
+        addReplacement(b, 436356000000L, "America/Anchorage", "America/Yakutat");
+        addReplacement(b, 436363200000L, "America/Anchorage", "America/Nome");
+        addReplacement(b, 1547978400000L, "America/Anchorage", "America/Metlakatla");
+        addReplacement(b, 341402400000L, "America/Anchorage", "America/Sitka");;
+
+        tzIdsBuilder.addCountryMappings(b);
+        assertEquals(tzIdsBuilder.build(), outputData.timeZoneIds);
+    }
+
+    private static void addReplacement(TzIdsProto.CountryMapping.Builder builder,
+            long fromMillis, String replacementId, String replacedId) {
+        TzIdsProto.TimeZoneReplacement replacement =
+                TzIdsProto.TimeZoneReplacement.newBuilder()
+                        .setReplacedId(replacedId)
+                        .setReplacementId(replacementId)
+                        .setFromMillis(fromMillis)
+                        .build();
+        builder.addTimeZoneReplacements(replacement);
+    }
+
+    static class OutputData {
+        final String tzLookupXml;
+        final TzIdsProto.TimeZoneIds timeZoneIds;
+
+        OutputData(String tzLookupXml, TzIdsProto.TimeZoneIds timeZoneIds) {
+            this.tzLookupXml = tzLookupXml;
+            this.timeZoneIds = timeZoneIds;
         }
     }
 
-    private String generateTzLookupXml(CountryZonesFile.Country country,
+    private OutputData generateOutputData(CountryZonesFile.Country country,
             List<ZoneTabFile.CountryEntry> zoneTabEntries, Map<String, String> backwardLinks)
             throws Exception {
 
@@ -606,16 +744,23 @@
         String zoneTabFile = createZoneTabFile(zoneTabEntries);
         String backwardFile = createBackwardFile(backwardLinks);
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertTrue(tzLookupGenerator.execute());
 
-        Path outputFilePath = Paths.get(outputFile);
-        assertTrue(Files.exists(outputFilePath));
+        Path tzLookupFilePath = checkFileExists(tzLookupFile);
+        String tzLookupXml = readFileToString(tzLookupFilePath);
 
-        return readFileToString(outputFilePath);
+        Path tzIdsFilePath = checkFileExists(tzIdsFile);
+        String timeZoneIdsText = readFileToString(tzIdsFilePath);
+        TzIdsProto.TimeZoneIds.Builder timeZoneIdsBuilder =
+                TzIdsProto.TimeZoneIds.newBuilder();
+        TextFormat.merge(timeZoneIdsText, timeZoneIdsBuilder);
+
+        return new OutputData(tzLookupXml, timeZoneIdsBuilder.build());
     }
 
     private void generateTzLookupXmlExpectFailure(CountryZonesFile.Country country,
@@ -628,10 +773,11 @@
         String zoneTabFile = createZoneTabFile(zoneTabEntries);
         String backwardFile = createBackwardFile(backwardLinks);
 
-        String outputFile = Files.createTempFile(tempDir, "out", null /* suffix */).toString();
+        String tzLookupFile = createTempFileName("tzlookup");
+        String tzIdsFile = createTempFileName("tzids");
 
-        TzLookupGenerator tzLookupGenerator =
-                new TzLookupGenerator(countryZonesFile, zoneTabFile, backwardFile, outputFile);
+        TzLookupGenerator tzLookupGenerator = new TzLookupGenerator(
+                countryZonesFile, zoneTabFile, backwardFile, tzLookupFile, tzIdsFile);
         assertFalse(tzLookupGenerator.execute());
     }
 
@@ -657,7 +803,7 @@
             CountryZonesFile.Country... countries) {
         CountryZonesFile.CountryZones.Builder builder =
                 CountryZonesFile.CountryZones.newBuilder()
-                        .setIanaVersion(TimeZone.getTZDataVersion());
+                        .setIanaVersion(TZDB_VERSION);
         for (CountryZonesFile.Country country : countries) {
             builder.addCountries(country);
         }
@@ -855,8 +1001,14 @@
     }
 
     private static List<ZoneTabFile.CountryEntry> createValidZoneTabEntriesFr() {
-        return Arrays.asList(
-                new ZoneTabFile.CountryEntry("FR", "Europe/Paris"));
+        return Arrays.asList(new ZoneTabFile.CountryEntry("FR", "Europe/Paris"));
+    }
+
+    /** Returns a file name for a file that does not exist. */
+    private String createTempFileName(String fileNamePrefix) throws IOException {
+        Path tempFile = Files.createTempFile(tempDir, fileNamePrefix, null /* suffix */);
+        Files.delete(tempFile);
+        return tempFile.toString();
     }
 
     private String createBackwardFile(Map<String, String> links) throws Exception {
@@ -866,10 +1018,8 @@
         return TestUtils.createFile(tempDir, lines.toArray(new String[0]));
     }
 
-    private static Map<String, String> createValidBackwardLinks() {
-        Map<String, String> map = new HashMap<>();
-        map.put("America/Godthab", "America/Nuuk");
-        return map;
+    private static Map<String, String> createEmptyBackwardLinks() {
+        return new HashMap<>();
     }
 
     private static Country parseCountry(String text) throws Exception {
@@ -878,4 +1028,14 @@
         return builder.build();
     }
 
+    private static Path checkFileExists(String fileName) {
+        Path filePath = Paths.get(fileName);
+        assertTrue("File " + filePath + " unexpectedly missing", Files.exists(filePath));
+        return filePath;
+    }
+
+    private static void assertFileMissing(String fileName) throws IOException {
+        Path filePath = Paths.get(fileName);
+        assertFalse("File " + filePath + " unexpectedly exists", Files.exists(filePath));
+    }
 }
diff --git a/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneTreeTest.java b/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneTreeTest.java
index e93c380..3986215 100644
--- a/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneTreeTest.java
+++ b/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneTreeTest.java
@@ -23,7 +23,7 @@
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 
-import static com.android.libcore.timezone.tzlookup.proto.CountryZonesFile.Country;
+import static com.android.libcore.timezone.countryzones.proto.CountryZonesFile.Country;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
diff --git a/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneUsageTest.java b/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneUsageTest.java
index b1a13b9..eae3ec1 100644
--- a/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneUsageTest.java
+++ b/input_tools/android/tzlookup_generator/src/test/java/com/android/libcore/timezone/tzlookup/zonetree/CountryZoneUsageTest.java
@@ -22,13 +22,14 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 public class CountryZoneUsageTest {
 
     @Test
-    public void testGetIsCode() {
+    public void testGetIsoCode() {
         CountryZoneUsage countryZoneUsage = new CountryZoneUsage("us");
         assertEquals("us", countryZoneUsage.getIsoCode());
     }
@@ -48,15 +49,23 @@
     @Test
     public void testWithEntry() {
         CountryZoneUsage countryZoneUsage = new CountryZoneUsage("us");
-        String usZoneId = "America/Boise";
+
+        String usZoneId1 = "America/Boise";
+        countryZoneUsage.addEntry(usZoneId1, null /* notUsedAfterInstant */, null /* altTzId */);
+        assertTrue(countryZoneUsage.hasEntry(usZoneId1));
+        assertNull(countryZoneUsage.getNotUsedAfterInstant(usZoneId1));
+        assertNull(null, countryZoneUsage.getNotUsedReplacementId(usZoneId1));
+
+        String usZoneId2 = "America/Los_Angeles";
         Instant instant = Instant.ofEpochSecond(1234);
-        countryZoneUsage.addEntry(usZoneId, instant);
+        countryZoneUsage.addEntry(usZoneId2, instant, usZoneId1 /* notUsedReplacementId */);
+        assertTrue(countryZoneUsage.hasEntry(usZoneId2));
+        assertEquals(instant, countryZoneUsage.getNotUsedAfterInstant(usZoneId2));
+        assertEquals(usZoneId1, countryZoneUsage.getNotUsedReplacementId(usZoneId2));
 
-        assertTrue(countryZoneUsage.hasEntry(usZoneId));
-        assertEquals(instant, countryZoneUsage.getNotUsedAfterInstant(usZoneId));
-
+        // Duplicate IDs are not allowed.
         try {
-            countryZoneUsage.addEntry(usZoneId, instant);
+            countryZoneUsage.addEntry(usZoneId1, instant, "" /* notUsedReplacementId */);
             fail();
         } catch (IllegalArgumentException expected) {
         }
diff --git a/input_tools/android/zone_compactor/main/java/ZoneCompactor.java b/input_tools/android/zone_compactor/main/java/ZoneCompactor.java
index c3c1089..5cc076a 100644
--- a/input_tools/android/zone_compactor/main/java/ZoneCompactor.java
+++ b/input_tools/android/zone_compactor/main/java/ZoneCompactor.java
@@ -17,7 +17,7 @@
 import java.io.*;
 import java.util.*;
 
-// usage: java ZoneCompiler <setup file> <data directory> <output directory> <tzdata version>
+// usage: java ZoneCompactor <setup file> <data directory> <output directory> <tzdata version>
 //
 // Compile a set of tzfile-formatted files into a single file containing an index.
 //
@@ -43,13 +43,13 @@
   private static final int MAXNAME = 40;
 
   // Zone name synonyms.
-  private Map<String,String> links = new HashMap<String,String>();
+  private Map<String,String> links = new HashMap<>();
 
   // File offsets by zone name.
-  private Map<String,Integer> offsets = new HashMap<String,Integer>();
+  private Map<String,Integer> offsets = new HashMap<>();
 
   // File lengths by zone name.
-  private Map<String,Integer> lengths = new HashMap<String,Integer>();
+  private Map<String,Integer> lengths = new HashMap<>();
 
   // Concatenate the contents of 'inFile' onto 'out'.
   private static void copyFile(File inFile, OutputStream out) throws Exception {
@@ -72,7 +72,8 @@
     out.flush();
   }
 
-  public ZoneCompactor(String setupFile, String dataDirectory, String zoneTabFile, String outputDirectory, String version) throws Exception {
+  public ZoneCompactor(String setupFile, String dataDirectory, String outputDirectory,
+          String version) throws Exception {
     // Read the setup file and concatenate all the data.
     ByteArrayOutputStream allData = new ByteArrayOutputStream();
     BufferedReader reader = new BufferedReader(new FileReader(setupFile));
@@ -80,19 +81,20 @@
     int offset = 0;
     while ((s = reader.readLine()) != null) {
       s = s.trim();
-      if (s.startsWith("Link")) {
-        StringTokenizer st = new StringTokenizer(s);
-        st.nextToken();
+      StringTokenizer st = new StringTokenizer(s);
+      String lineType = st.nextToken();
+      if (lineType.startsWith("Link")) {
         String to = st.nextToken();
         String from = st.nextToken();
         links.put(from, to);
-      } else {
-        String link = links.get(s);
+      } else if (lineType.startsWith("Zone")) {
+        String zoneId = st.nextToken();
+        String link = links.get(zoneId);
         if (link == null) {
-          File sourceFile = new File(dataDirectory, s);
+          File sourceFile = new File(dataDirectory, zoneId);
           long length = sourceFile.length();
-          offsets.put(s, offset);
-          lengths.put(s, (int) length);
+          offsets.put(zoneId, offset);
+          lengths.put(zoneId, (int) length);
 
           offset += length;
           copyFile(sourceFile, allData);
@@ -102,9 +104,7 @@
     reader.close();
 
     // Fill in fields for links.
-    Iterator<String> it = links.keySet().iterator();
-    while (it.hasNext()) {
-      String from = it.next();
+    for (String from : links.keySet()) {
       String to = links.get(from);
 
       offsets.put(from, offsets.get(to));
@@ -120,18 +120,22 @@
     // byte[12] tzdata_version -- 'tzdata2012f\0'
     // int index_offset -- so we can slip in extra header fields in a backwards-compatible way
     // int data_offset
-    // int zonetab_offset
+    // int final_offset
 
     // tzdata_version
     f.write(toAscii(new byte[12], version));
 
-    // Write dummy values for the three offsets, and remember where we need to seek back to later
+    // Write placeholder values for the offsets, and remember where we need to seek back to later
     // when we have the real values.
     int index_offset_offset = (int) f.getFilePointer();
     f.writeInt(0);
     int data_offset_offset = (int) f.getFilePointer();
     f.writeInt(0);
-    int zonetab_offset_offset = (int) f.getFilePointer();
+    // The final offset serves as a placeholder for sections that might be added in future and
+    // ensures we know the size of the final "real" section. Relying on the last section ending at
+    // EOF would make it harder to append sections to the end of the file in a backward compatible
+    // way.
+    int final_offset_offset = (int) f.getFilePointer();
     f.writeInt(0);
 
     int index_offset = (int) f.getFilePointer();
@@ -140,9 +144,7 @@
     ArrayList<String> sortedOlsonIds = new ArrayList<String>();
     sortedOlsonIds.addAll(offsets.keySet());
     Collections.sort(sortedOlsonIds);
-    it = sortedOlsonIds.iterator();
-    while (it.hasNext()) {
-      String zoneName = it.next();
+    for (String zoneName : sortedOlsonIds) {
       if (zoneName.length() >= MAXNAME) {
         throw new RuntimeException("zone filename too long: " + zoneName.length());
       }
@@ -164,25 +166,15 @@
     // Write the data.
     f.write(allData.toByteArray());
 
-    int zonetab_offset = (int) f.getFilePointer();
-
-    // Copy the zone.tab.
-    reader = new BufferedReader(new FileReader(zoneTabFile));
-    while ((s = reader.readLine()) != null) {
-      if (!s.startsWith("#")) {
-        f.writeBytes(s);
-        f.write('\n');
-      }
-    }
-    reader.close();
+    int final_offset = (int) f.getFilePointer();
 
     // Go back and fix up the offsets in the header.
     f.seek(index_offset_offset);
     f.writeInt(index_offset);
     f.seek(data_offset_offset);
     f.writeInt(data_offset);
-    f.seek(zonetab_offset_offset);
-    f.writeInt(zonetab_offset);
+    f.seek(final_offset_offset);
+    f.writeInt(final_offset);
 
     f.close();
   }
@@ -198,10 +190,11 @@
   }
 
   public static void main(String[] args) throws Exception {
-    if (args.length != 5) {
-      System.err.println("usage: java ZoneCompactor <setup file> <data directory> <zone.tab file> <output directory> <tzdata version>");
-      System.exit(0);
+    if (args.length != 4) {
+      System.err.println("usage: java ZoneCompactor <setup file> <data directory>"
+              + " <output directory> <tzdata version>");
+      System.exit(1);
     }
-    new ZoneCompactor(args[0], args[1], args[2], args[3], args[4]);
+    new ZoneCompactor(args[0], args[1], args[2], args[3]);
   }
 }
diff --git a/output_data/Android.bp b/output_data/Android.bp
index e56a078..abe8e36 100644
--- a/output_data/Android.bp
+++ b/output_data/Android.bp
@@ -55,7 +55,7 @@
 }
 
 // tzdata packaged into a jar for use in robolectric
-java_genrule {
+java_genrule_host {
     name: "robolectric_tzdata",
     out: ["robolectric_tzdata.jar"],
     tools: ["soong_zip"],
diff --git a/output_data/android/tzids.prototxt b/output_data/android/tzids.prototxt
new file mode 100644
index 0000000..c97b964
--- /dev/null
+++ b/output_data/android/tzids.prototxt
@@ -0,0 +1,1980 @@
+# Autogenerated file - DO NOT EDIT.
+ianaVersion: "2020a"
+countryMappings {
+  isoCode: "ad"
+  timeZoneIds: "Europe/Andorra"
+}
+countryMappings {
+  isoCode: "ae"
+  timeZoneIds: "Asia/Dubai"
+}
+countryMappings {
+  isoCode: "af"
+  timeZoneIds: "Asia/Kabul"
+}
+countryMappings {
+  isoCode: "ag"
+  timeZoneIds: "America/Antigua"
+}
+countryMappings {
+  isoCode: "ai"
+  timeZoneIds: "America/Anguilla"
+}
+countryMappings {
+  isoCode: "al"
+  timeZoneIds: "Europe/Tirane"
+}
+countryMappings {
+  isoCode: "am"
+  timeZoneIds: "Asia/Yerevan"
+}
+countryMappings {
+  isoCode: "ao"
+  timeZoneIds: "Africa/Luanda"
+}
+countryMappings {
+  isoCode: "aq"
+  timeZoneIds: "Antarctica/McMurdo"
+  timeZoneIds: "Antarctica/DumontDUrville"
+  timeZoneIds: "Antarctica/Casey"
+  timeZoneIds: "Antarctica/Davis"
+  timeZoneIds: "Antarctica/Mawson"
+  timeZoneIds: "Antarctica/Vostok"
+  timeZoneIds: "Antarctica/Syowa"
+  timeZoneIds: "Antarctica/Troll"
+  timeZoneIds: "Antarctica/Rothera"
+  timeZoneIds: "Antarctica/Palmer"
+}
+countryMappings {
+  isoCode: "ar"
+  timeZoneIds: "America/Argentina/Buenos_Aires"
+  timeZoneIds: "America/Argentina/San_Luis"
+  timeZoneLinks {
+    alternativeId: "America/Buenos_Aires"
+    preferredId: "America/Argentina/Buenos_Aires"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Cordoba"
+    preferredId: "America/Argentina/Cordoba"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Rosario"
+    preferredId: "America/Argentina/Cordoba"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Mendoza"
+    preferredId: "America/Argentina/Mendoza"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Jujuy"
+    preferredId: "America/Argentina/Jujuy"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Argentina/ComodRivadavia"
+    preferredId: "America/Argentina/Catamarca"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Catamarca"
+    preferredId: "America/Argentina/Catamarca"
+  }
+  timeZoneReplacements {
+    replacedId: "America/Argentina/Cordoba"
+    replacementId: "America/Argentina/Buenos_Aires"
+    fromMillis: 687931200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Argentina/Mendoza"
+    replacementId: "America/Argentina/Buenos_Aires"
+    fromMillis: 1237082400000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Argentina/Tucuman"
+    replacementId: "America/Argentina/Buenos_Aires"
+    fromMillis: 1087099200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Argentina/Salta"
+    replacementId: "America/Argentina/Buenos_Aires"
+    fromMillis: 1096171200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Argentina/San_Juan"
+    replacementId: "America/Argentina/Buenos_Aires"
+    fromMillis: 1090728000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Argentina/Jujuy"
+    replacementId: "America/Argentina/Buenos_Aires"
+    fromMillis: 687931200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Argentina/Catamarca"
+    replacementId: "America/Argentina/Buenos_Aires"
+    fromMillis: 1087704000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Argentina/La_Rioja"
+    replacementId: "America/Argentina/Buenos_Aires"
+    fromMillis: 687931200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Argentina/Rio_Gallegos"
+    replacementId: "America/Argentina/Buenos_Aires"
+    fromMillis: 673588800000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Argentina/Ushuaia"
+    replacementId: "America/Argentina/Buenos_Aires"
+    fromMillis: 1087704000000
+  }
+}
+countryMappings {
+  isoCode: "as"
+  timeZoneIds: "Pacific/Pago_Pago"
+  timeZoneLinks {
+    alternativeId: "Pacific/Samoa"
+    preferredId: "Pacific/Pago_Pago"
+  }
+  timeZoneLinks {
+    alternativeId: "US/Samoa"
+    preferredId: "Pacific/Pago_Pago"
+  }
+}
+countryMappings {
+  isoCode: "at"
+  timeZoneIds: "Europe/Vienna"
+}
+countryMappings {
+  isoCode: "au"
+  timeZoneIds: "Australia/Sydney"
+  timeZoneIds: "Australia/Brisbane"
+  timeZoneIds: "Antarctica/Macquarie"
+  timeZoneIds: "Australia/Lord_Howe"
+  timeZoneIds: "Australia/Adelaide"
+  timeZoneIds: "Australia/Darwin"
+  timeZoneIds: "Australia/Perth"
+  timeZoneIds: "Australia/Eucla"
+  timeZoneLinks {
+    alternativeId: "Australia/ACT"
+    preferredId: "Australia/Sydney"
+  }
+  timeZoneLinks {
+    alternativeId: "Australia/Canberra"
+    preferredId: "Australia/Sydney"
+  }
+  timeZoneLinks {
+    alternativeId: "Australia/NSW"
+    preferredId: "Australia/Sydney"
+  }
+  timeZoneLinks {
+    alternativeId: "Australia/Victoria"
+    preferredId: "Australia/Melbourne"
+  }
+  timeZoneLinks {
+    alternativeId: "Australia/Tasmania"
+    preferredId: "Australia/Hobart"
+  }
+  timeZoneLinks {
+    alternativeId: "Australia/Queensland"
+    preferredId: "Australia/Brisbane"
+  }
+  timeZoneLinks {
+    alternativeId: "Australia/LHI"
+    preferredId: "Australia/Lord_Howe"
+  }
+  timeZoneLinks {
+    alternativeId: "Australia/South"
+    preferredId: "Australia/Adelaide"
+  }
+  timeZoneLinks {
+    alternativeId: "Australia/Yancowinna"
+    preferredId: "Australia/Broken_Hill"
+  }
+  timeZoneLinks {
+    alternativeId: "Australia/North"
+    preferredId: "Australia/Darwin"
+  }
+  timeZoneLinks {
+    alternativeId: "Australia/West"
+    preferredId: "Australia/Perth"
+  }
+  timeZoneReplacements {
+    replacedId: "Australia/Melbourne"
+    replacementId: "Australia/Sydney"
+    fromMillis: 796147200000
+  }
+  timeZoneReplacements {
+    replacedId: "Australia/Hobart"
+    replacementId: "Australia/Sydney"
+    fromMillis: 1193500800000
+  }
+  timeZoneReplacements {
+    replacedId: "Australia/Currie"
+    replacementId: "Australia/Sydney"
+    fromMillis: 37728000000
+  }
+  timeZoneReplacements {
+    replacedId: "Australia/Lindeman"
+    replacementId: "Australia/Brisbane"
+    fromMillis: 762883200000
+  }
+  timeZoneReplacements {
+    replacedId: "Australia/Broken_Hill"
+    replacementId: "Australia/Adelaide"
+    fromMillis: 796149000000
+  }
+}
+countryMappings {
+  isoCode: "aw"
+  timeZoneIds: "America/Aruba"
+}
+countryMappings {
+  isoCode: "ax"
+  timeZoneIds: "Europe/Mariehamn"
+}
+countryMappings {
+  isoCode: "az"
+  timeZoneIds: "Asia/Baku"
+}
+countryMappings {
+  isoCode: "ba"
+  timeZoneIds: "Europe/Sarajevo"
+}
+countryMappings {
+  isoCode: "bb"
+  timeZoneIds: "America/Barbados"
+}
+countryMappings {
+  isoCode: "bd"
+  timeZoneIds: "Asia/Dhaka"
+  timeZoneLinks {
+    alternativeId: "Asia/Dacca"
+    preferredId: "Asia/Dhaka"
+  }
+}
+countryMappings {
+  isoCode: "be"
+  timeZoneIds: "Europe/Brussels"
+}
+countryMappings {
+  isoCode: "bf"
+  timeZoneIds: "Africa/Ouagadougou"
+}
+countryMappings {
+  isoCode: "bg"
+  timeZoneIds: "Europe/Sofia"
+}
+countryMappings {
+  isoCode: "bh"
+  timeZoneIds: "Asia/Bahrain"
+}
+countryMappings {
+  isoCode: "bi"
+  timeZoneIds: "Africa/Bujumbura"
+}
+countryMappings {
+  isoCode: "bj"
+  timeZoneIds: "Africa/Porto-Novo"
+}
+countryMappings {
+  isoCode: "bl"
+  timeZoneIds: "America/St_Barthelemy"
+}
+countryMappings {
+  isoCode: "bm"
+  timeZoneIds: "Atlantic/Bermuda"
+}
+countryMappings {
+  isoCode: "bn"
+  timeZoneIds: "Asia/Brunei"
+}
+countryMappings {
+  isoCode: "bo"
+  timeZoneIds: "America/La_Paz"
+}
+countryMappings {
+  isoCode: "bq"
+  timeZoneIds: "America/Kralendijk"
+}
+countryMappings {
+  isoCode: "br"
+  timeZoneIds: "America/Noronha"
+  timeZoneIds: "America/Sao_Paulo"
+  timeZoneIds: "America/Manaus"
+  timeZoneIds: "America/Rio_Branco"
+  timeZoneLinks {
+    alternativeId: "Brazil/DeNoronha"
+    preferredId: "America/Noronha"
+  }
+  timeZoneLinks {
+    alternativeId: "Brazil/East"
+    preferredId: "America/Sao_Paulo"
+  }
+  timeZoneLinks {
+    alternativeId: "Brazil/West"
+    preferredId: "America/Manaus"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Porto_Acre"
+    preferredId: "America/Rio_Branco"
+  }
+  timeZoneLinks {
+    alternativeId: "Brazil/Acre"
+    preferredId: "America/Rio_Branco"
+  }
+  timeZoneReplacements {
+    replacedId: "America/Bahia"
+    replacementId: "America/Sao_Paulo"
+    fromMillis: 1550368800000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Santarem"
+    replacementId: "America/Sao_Paulo"
+    fromMillis: 1214280000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Recife"
+    replacementId: "America/Sao_Paulo"
+    fromMillis: 1330221600000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Fortaleza"
+    replacementId: "America/Sao_Paulo"
+    fromMillis: 972180000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Belem"
+    replacementId: "America/Sao_Paulo"
+    fromMillis: 1013911200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Maceio"
+    replacementId: "America/Sao_Paulo"
+    fromMillis: 824004000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Araguaina"
+    replacementId: "America/Sao_Paulo"
+    fromMillis: 1361066400000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Cuiaba"
+    replacementId: "America/Manaus"
+    fromMillis: 1550372400000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Campo_Grande"
+    replacementId: "America/Manaus"
+    fromMillis: 1076814000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Porto_Velho"
+    replacementId: "America/Manaus"
+    fromMillis: 761713200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Boa_Vista"
+    replacementId: "America/Manaus"
+    fromMillis: 971578800000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Eirunepe"
+    replacementId: "America/Rio_Branco"
+    fromMillis: 761716800000
+  }
+}
+countryMappings {
+  isoCode: "bs"
+  timeZoneIds: "America/Nassau"
+}
+countryMappings {
+  isoCode: "bt"
+  timeZoneIds: "Asia/Thimphu"
+  timeZoneLinks {
+    alternativeId: "Asia/Thimbu"
+    preferredId: "Asia/Thimphu"
+  }
+}
+countryMappings {
+  isoCode: "bw"
+  timeZoneIds: "Africa/Gaborone"
+}
+countryMappings {
+  isoCode: "by"
+  timeZoneIds: "Europe/Minsk"
+}
+countryMappings {
+  isoCode: "bz"
+  timeZoneIds: "America/Belize"
+}
+countryMappings {
+  isoCode: "ca"
+  timeZoneIds: "America/Toronto"
+  timeZoneIds: "America/Vancouver"
+  timeZoneIds: "America/Edmonton"
+  timeZoneIds: "America/Winnipeg"
+  timeZoneIds: "America/Halifax"
+  timeZoneIds: "America/St_Johns"
+  timeZoneIds: "America/Blanc-Sablon"
+  timeZoneIds: "America/Atikokan"
+  timeZoneIds: "America/Regina"
+  timeZoneIds: "America/Whitehorse"
+  timeZoneLinks {
+    alternativeId: "America/Montreal"
+    preferredId: "America/Toronto"
+  }
+  timeZoneLinks {
+    alternativeId: "Canada/Eastern"
+    preferredId: "America/Toronto"
+  }
+  timeZoneLinks {
+    alternativeId: "Canada/Pacific"
+    preferredId: "America/Vancouver"
+  }
+  timeZoneLinks {
+    alternativeId: "Canada/Mountain"
+    preferredId: "America/Edmonton"
+  }
+  timeZoneLinks {
+    alternativeId: "Canada/Central"
+    preferredId: "America/Winnipeg"
+  }
+  timeZoneLinks {
+    alternativeId: "Canada/Atlantic"
+    preferredId: "America/Halifax"
+  }
+  timeZoneLinks {
+    alternativeId: "Canada/Newfoundland"
+    preferredId: "America/St_Johns"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Coral_Harbour"
+    preferredId: "America/Atikokan"
+  }
+  timeZoneLinks {
+    alternativeId: "Canada/Saskatchewan"
+    preferredId: "America/Regina"
+  }
+  timeZoneLinks {
+    alternativeId: "Canada/Yukon"
+    preferredId: "America/Whitehorse"
+  }
+  timeZoneReplacements {
+    replacedId: "America/Moncton"
+    replacementId: "America/Halifax"
+    fromMillis: 1162098000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Glace_Bay"
+    replacementId: "America/Halifax"
+    fromMillis: 57733200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Goose_Bay"
+    replacementId: "America/Halifax"
+    fromMillis: 1299996000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Thunder_Bay"
+    replacementId: "America/Toronto"
+    fromMillis: 120636000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Iqaluit"
+    replacementId: "America/Toronto"
+    fromMillis: 972802800000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Nipigon"
+    replacementId: "America/Toronto"
+    fromMillis: 89186400000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Pangnirtung"
+    replacementId: "America/Toronto"
+    fromMillis: 796806000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Swift_Current"
+    replacementId: "America/Winnipeg"
+    fromMillis: 73472400000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Rankin_Inlet"
+    replacementId: "America/Winnipeg"
+    fromMillis: 1130659200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Rainy_River"
+    replacementId: "America/Winnipeg"
+    fromMillis: 986112000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Resolute"
+    replacementId: "America/Winnipeg"
+    fromMillis: 1173600000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Yellowknife"
+    replacementId: "America/Edmonton"
+    fromMillis: 309945600000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Dawson_Creek"
+    replacementId: "America/Edmonton"
+    fromMillis: 1583661600000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Creston"
+    replacementId: "America/Edmonton"
+    fromMillis: 84013200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Fort_Nelson"
+    replacementId: "America/Edmonton"
+    fromMillis: 1425808800000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Inuvik"
+    replacementId: "America/Edmonton"
+    fromMillis: 294228000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Cambridge_Bay"
+    replacementId: "America/Edmonton"
+    fromMillis: 986115600000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Dawson"
+    replacementId: "America/Edmonton"
+    fromMillis: 120646800000
+  }
+}
+countryMappings {
+  isoCode: "cc"
+  timeZoneIds: "Indian/Cocos"
+}
+countryMappings {
+  isoCode: "cd"
+  timeZoneIds: "Africa/Lubumbashi"
+  timeZoneIds: "Africa/Kinshasa"
+}
+countryMappings {
+  isoCode: "cf"
+  timeZoneIds: "Africa/Bangui"
+}
+countryMappings {
+  isoCode: "cg"
+  timeZoneIds: "Africa/Brazzaville"
+}
+countryMappings {
+  isoCode: "ch"
+  timeZoneIds: "Europe/Zurich"
+}
+countryMappings {
+  isoCode: "ci"
+  timeZoneIds: "Africa/Abidjan"
+  timeZoneLinks {
+    alternativeId: "Africa/Timbuktu"
+    preferredId: "Africa/Abidjan"
+  }
+}
+countryMappings {
+  isoCode: "ck"
+  timeZoneIds: "Pacific/Rarotonga"
+}
+countryMappings {
+  isoCode: "cl"
+  timeZoneIds: "America/Punta_Arenas"
+  timeZoneIds: "America/Santiago"
+  timeZoneIds: "Pacific/Easter"
+  timeZoneLinks {
+    alternativeId: "Chile/Continental"
+    preferredId: "America/Santiago"
+  }
+  timeZoneLinks {
+    alternativeId: "Chile/EasterIsland"
+    preferredId: "Pacific/Easter"
+  }
+}
+countryMappings {
+  isoCode: "cm"
+  timeZoneIds: "Africa/Douala"
+}
+countryMappings {
+  isoCode: "cn"
+  timeZoneIds: "Asia/Shanghai"
+  timeZoneIds: "Asia/Urumqi"
+  timeZoneLinks {
+    alternativeId: "Asia/Chongqing"
+    preferredId: "Asia/Shanghai"
+  }
+  timeZoneLinks {
+    alternativeId: "Asia/Chungking"
+    preferredId: "Asia/Shanghai"
+  }
+  timeZoneLinks {
+    alternativeId: "Asia/Harbin"
+    preferredId: "Asia/Shanghai"
+  }
+  timeZoneLinks {
+    alternativeId: "PRC"
+    preferredId: "Asia/Shanghai"
+  }
+  timeZoneLinks {
+    alternativeId: "Asia/Kashgar"
+    preferredId: "Asia/Urumqi"
+  }
+}
+countryMappings {
+  isoCode: "co"
+  timeZoneIds: "America/Bogota"
+}
+countryMappings {
+  isoCode: "cr"
+  timeZoneIds: "America/Costa_Rica"
+}
+countryMappings {
+  isoCode: "cu"
+  timeZoneIds: "America/Havana"
+  timeZoneLinks {
+    alternativeId: "Cuba"
+    preferredId: "America/Havana"
+  }
+}
+countryMappings {
+  isoCode: "cv"
+  timeZoneIds: "Atlantic/Cape_Verde"
+}
+countryMappings {
+  isoCode: "cw"
+  timeZoneIds: "America/Curacao"
+}
+countryMappings {
+  isoCode: "cx"
+  timeZoneIds: "Indian/Christmas"
+}
+countryMappings {
+  isoCode: "cy"
+  timeZoneIds: "Asia/Nicosia"
+  timeZoneIds: "Asia/Famagusta"
+}
+countryMappings {
+  isoCode: "cz"
+  timeZoneIds: "Europe/Prague"
+}
+countryMappings {
+  isoCode: "de"
+  timeZoneIds: "Europe/Berlin"
+  timeZoneReplacements {
+    replacedId: "Europe/Busingen"
+    replacementId: "Europe/Berlin"
+    fromMillis: 338950800000
+  }
+}
+countryMappings {
+  isoCode: "dj"
+  timeZoneIds: "Africa/Djibouti"
+}
+countryMappings {
+  isoCode: "dk"
+  timeZoneIds: "Europe/Copenhagen"
+}
+countryMappings {
+  isoCode: "dm"
+  timeZoneIds: "America/Dominica"
+}
+countryMappings {
+  isoCode: "do"
+  timeZoneIds: "America/Santo_Domingo"
+}
+countryMappings {
+  isoCode: "dz"
+  timeZoneIds: "Africa/Algiers"
+}
+countryMappings {
+  isoCode: "ec"
+  timeZoneIds: "America/Guayaquil"
+  timeZoneIds: "Pacific/Galapagos"
+}
+countryMappings {
+  isoCode: "ee"
+  timeZoneIds: "Europe/Tallinn"
+}
+countryMappings {
+  isoCode: "eg"
+  timeZoneIds: "Africa/Cairo"
+  timeZoneLinks {
+    alternativeId: "Egypt"
+    preferredId: "Africa/Cairo"
+  }
+}
+countryMappings {
+  isoCode: "eh"
+  timeZoneIds: "Africa/El_Aaiun"
+}
+countryMappings {
+  isoCode: "er"
+  timeZoneIds: "Africa/Asmara"
+}
+countryMappings {
+  isoCode: "es"
+  timeZoneIds: "Europe/Madrid"
+  timeZoneIds: "Atlantic/Canary"
+  timeZoneReplacements {
+    replacedId: "Africa/Ceuta"
+    replacementId: "Europe/Madrid"
+    fromMillis: 496803600000
+  }
+}
+countryMappings {
+  isoCode: "et"
+  timeZoneIds: "Africa/Addis_Ababa"
+}
+countryMappings {
+  isoCode: "fi"
+  timeZoneIds: "Europe/Helsinki"
+}
+countryMappings {
+  isoCode: "fj"
+  timeZoneIds: "Pacific/Fiji"
+}
+countryMappings {
+  isoCode: "fk"
+  timeZoneIds: "Atlantic/Stanley"
+}
+countryMappings {
+  isoCode: "fm"
+  timeZoneIds: "Pacific/Pohnpei"
+  timeZoneIds: "Pacific/Kosrae"
+  timeZoneIds: "Pacific/Chuuk"
+  timeZoneLinks {
+    alternativeId: "Pacific/Ponape"
+    preferredId: "Pacific/Pohnpei"
+  }
+  timeZoneLinks {
+    alternativeId: "Pacific/Truk"
+    preferredId: "Pacific/Chuuk"
+  }
+  timeZoneLinks {
+    alternativeId: "Pacific/Yap"
+    preferredId: "Pacific/Chuuk"
+  }
+}
+countryMappings {
+  isoCode: "fo"
+  timeZoneIds: "Atlantic/Faroe"
+  timeZoneLinks {
+    alternativeId: "Atlantic/Faeroe"
+    preferredId: "Atlantic/Faroe"
+  }
+}
+countryMappings {
+  isoCode: "fr"
+  timeZoneIds: "Europe/Paris"
+}
+countryMappings {
+  isoCode: "ga"
+  timeZoneIds: "Africa/Libreville"
+}
+countryMappings {
+  isoCode: "gb"
+  timeZoneIds: "Europe/London"
+  timeZoneLinks {
+    alternativeId: "Europe/Belfast"
+    preferredId: "Europe/London"
+  }
+  timeZoneLinks {
+    alternativeId: "GB"
+    preferredId: "Europe/London"
+  }
+  timeZoneLinks {
+    alternativeId: "GB-Eire"
+    preferredId: "Europe/London"
+  }
+}
+countryMappings {
+  isoCode: "gd"
+  timeZoneIds: "America/Grenada"
+}
+countryMappings {
+  isoCode: "ge"
+  timeZoneIds: "Asia/Tbilisi"
+}
+countryMappings {
+  isoCode: "gf"
+  timeZoneIds: "America/Cayenne"
+}
+countryMappings {
+  isoCode: "gg"
+  timeZoneIds: "Europe/Guernsey"
+}
+countryMappings {
+  isoCode: "gh"
+  timeZoneIds: "Africa/Accra"
+}
+countryMappings {
+  isoCode: "gi"
+  timeZoneIds: "Europe/Gibraltar"
+}
+countryMappings {
+  isoCode: "gl"
+  timeZoneIds: "America/Danmarkshavn"
+  timeZoneIds: "America/Scoresbysund"
+  timeZoneIds: "America/Nuuk"
+  timeZoneIds: "America/Thule"
+  timeZoneLinks {
+    alternativeId: "America/Godthab"
+    preferredId: "America/Nuuk"
+  }
+}
+countryMappings {
+  isoCode: "gm"
+  timeZoneIds: "Africa/Banjul"
+}
+countryMappings {
+  isoCode: "gn"
+  timeZoneIds: "Africa/Conakry"
+}
+countryMappings {
+  isoCode: "gp"
+  timeZoneIds: "America/Guadeloupe"
+}
+countryMappings {
+  isoCode: "gq"
+  timeZoneIds: "Africa/Malabo"
+}
+countryMappings {
+  isoCode: "gr"
+  timeZoneIds: "Europe/Athens"
+}
+countryMappings {
+  isoCode: "gs"
+  timeZoneIds: "Atlantic/South_Georgia"
+}
+countryMappings {
+  isoCode: "gt"
+  timeZoneIds: "America/Guatemala"
+}
+countryMappings {
+  isoCode: "gu"
+  timeZoneIds: "Pacific/Guam"
+}
+countryMappings {
+  isoCode: "gw"
+  timeZoneIds: "Africa/Bissau"
+}
+countryMappings {
+  isoCode: "gy"
+  timeZoneIds: "America/Guyana"
+}
+countryMappings {
+  isoCode: "hk"
+  timeZoneIds: "Asia/Hong_Kong"
+  timeZoneLinks {
+    alternativeId: "Hongkong"
+    preferredId: "Asia/Hong_Kong"
+  }
+}
+countryMappings {
+  isoCode: "hn"
+  timeZoneIds: "America/Tegucigalpa"
+}
+countryMappings {
+  isoCode: "hr"
+  timeZoneIds: "Europe/Zagreb"
+}
+countryMappings {
+  isoCode: "ht"
+  timeZoneIds: "America/Port-au-Prince"
+}
+countryMappings {
+  isoCode: "hu"
+  timeZoneIds: "Europe/Budapest"
+}
+countryMappings {
+  isoCode: "id"
+  timeZoneIds: "Asia/Jayapura"
+  timeZoneIds: "Asia/Makassar"
+  timeZoneIds: "Asia/Jakarta"
+  timeZoneLinks {
+    alternativeId: "Asia/Ujung_Pandang"
+    preferredId: "Asia/Makassar"
+  }
+  timeZoneReplacements {
+    replacedId: "Asia/Pontianak"
+    replacementId: "Asia/Jakarta"
+    fromMillis: 567964800000
+  }
+}
+countryMappings {
+  isoCode: "ie"
+  timeZoneIds: "Europe/Dublin"
+  timeZoneLinks {
+    alternativeId: "Eire"
+    preferredId: "Europe/Dublin"
+  }
+}
+countryMappings {
+  isoCode: "il"
+  timeZoneIds: "Asia/Jerusalem"
+  timeZoneLinks {
+    alternativeId: "Asia/Tel_Aviv"
+    preferredId: "Asia/Jerusalem"
+  }
+  timeZoneLinks {
+    alternativeId: "Israel"
+    preferredId: "Asia/Jerusalem"
+  }
+}
+countryMappings {
+  isoCode: "im"
+  timeZoneIds: "Europe/Isle_of_Man"
+}
+countryMappings {
+  isoCode: "in"
+  timeZoneIds: "Asia/Kolkata"
+  timeZoneLinks {
+    alternativeId: "Asia/Calcutta"
+    preferredId: "Asia/Kolkata"
+  }
+}
+countryMappings {
+  isoCode: "io"
+  timeZoneIds: "Indian/Chagos"
+}
+countryMappings {
+  isoCode: "iq"
+  timeZoneIds: "Asia/Baghdad"
+}
+countryMappings {
+  isoCode: "ir"
+  timeZoneIds: "Asia/Tehran"
+  timeZoneLinks {
+    alternativeId: "Iran"
+    preferredId: "Asia/Tehran"
+  }
+}
+countryMappings {
+  isoCode: "is"
+  timeZoneIds: "Atlantic/Reykjavik"
+  timeZoneLinks {
+    alternativeId: "Iceland"
+    preferredId: "Atlantic/Reykjavik"
+  }
+}
+countryMappings {
+  isoCode: "it"
+  timeZoneIds: "Europe/Rome"
+}
+countryMappings {
+  isoCode: "je"
+  timeZoneIds: "Europe/Jersey"
+}
+countryMappings {
+  isoCode: "jm"
+  timeZoneIds: "America/Jamaica"
+  timeZoneLinks {
+    alternativeId: "Jamaica"
+    preferredId: "America/Jamaica"
+  }
+}
+countryMappings {
+  isoCode: "jo"
+  timeZoneIds: "Asia/Amman"
+}
+countryMappings {
+  isoCode: "jp"
+  timeZoneIds: "Asia/Tokyo"
+  timeZoneLinks {
+    alternativeId: "Japan"
+    preferredId: "Asia/Tokyo"
+  }
+}
+countryMappings {
+  isoCode: "ke"
+  timeZoneIds: "Africa/Nairobi"
+  timeZoneLinks {
+    alternativeId: "Africa/Asmera"
+    preferredId: "Africa/Nairobi"
+  }
+}
+countryMappings {
+  isoCode: "kg"
+  timeZoneIds: "Asia/Bishkek"
+}
+countryMappings {
+  isoCode: "kh"
+  timeZoneIds: "Asia/Phnom_Penh"
+}
+countryMappings {
+  isoCode: "ki"
+  timeZoneIds: "Pacific/Kiritimati"
+  timeZoneIds: "Pacific/Enderbury"
+  timeZoneIds: "Pacific/Tarawa"
+}
+countryMappings {
+  isoCode: "km"
+  timeZoneIds: "Indian/Comoro"
+}
+countryMappings {
+  isoCode: "kn"
+  timeZoneIds: "America/St_Kitts"
+}
+countryMappings {
+  isoCode: "kp"
+  timeZoneIds: "Asia/Pyongyang"
+}
+countryMappings {
+  isoCode: "kr"
+  timeZoneIds: "Asia/Seoul"
+  timeZoneLinks {
+    alternativeId: "ROK"
+    preferredId: "Asia/Seoul"
+  }
+}
+countryMappings {
+  isoCode: "kw"
+  timeZoneIds: "Asia/Kuwait"
+}
+countryMappings {
+  isoCode: "ky"
+  timeZoneIds: "America/Cayman"
+}
+countryMappings {
+  isoCode: "kz"
+  timeZoneIds: "Asia/Almaty"
+  timeZoneIds: "Asia/Oral"
+  timeZoneReplacements {
+    replacedId: "Asia/Qostanay"
+    replacementId: "Asia/Almaty"
+    fromMillis: 1099170000000
+  }
+  timeZoneReplacements {
+    replacedId: "Asia/Aqtau"
+    replacementId: "Asia/Oral"
+    fromMillis: 1099173600000
+  }
+  timeZoneReplacements {
+    replacedId: "Asia/Qyzylorda"
+    replacementId: "Asia/Oral"
+    fromMillis: 1545328800000
+  }
+  timeZoneReplacements {
+    replacedId: "Asia/Aqtobe"
+    replacementId: "Asia/Oral"
+    fromMillis: 1545328800000
+  }
+  timeZoneReplacements {
+    replacedId: "Asia/Atyrau"
+    replacementId: "Asia/Oral"
+    fromMillis: 922572000000
+  }
+}
+countryMappings {
+  isoCode: "la"
+  timeZoneIds: "Asia/Vientiane"
+}
+countryMappings {
+  isoCode: "lb"
+  timeZoneIds: "Asia/Beirut"
+}
+countryMappings {
+  isoCode: "lc"
+  timeZoneIds: "America/St_Lucia"
+}
+countryMappings {
+  isoCode: "li"
+  timeZoneIds: "Europe/Vaduz"
+}
+countryMappings {
+  isoCode: "lk"
+  timeZoneIds: "Asia/Colombo"
+}
+countryMappings {
+  isoCode: "lr"
+  timeZoneIds: "Africa/Monrovia"
+}
+countryMappings {
+  isoCode: "ls"
+  timeZoneIds: "Africa/Maseru"
+}
+countryMappings {
+  isoCode: "lt"
+  timeZoneIds: "Europe/Vilnius"
+}
+countryMappings {
+  isoCode: "lu"
+  timeZoneIds: "Europe/Luxembourg"
+}
+countryMappings {
+  isoCode: "lv"
+  timeZoneIds: "Europe/Riga"
+}
+countryMappings {
+  isoCode: "ly"
+  timeZoneIds: "Africa/Tripoli"
+  timeZoneLinks {
+    alternativeId: "Libya"
+    preferredId: "Africa/Tripoli"
+  }
+}
+countryMappings {
+  isoCode: "ma"
+  timeZoneIds: "Africa/Casablanca"
+}
+countryMappings {
+  isoCode: "mc"
+  timeZoneIds: "Europe/Monaco"
+}
+countryMappings {
+  isoCode: "md"
+  timeZoneIds: "Europe/Chisinau"
+  timeZoneLinks {
+    alternativeId: "Europe/Tiraspol"
+    preferredId: "Europe/Chisinau"
+  }
+}
+countryMappings {
+  isoCode: "me"
+  timeZoneIds: "Europe/Podgorica"
+}
+countryMappings {
+  isoCode: "mf"
+  timeZoneIds: "America/Marigot"
+}
+countryMappings {
+  isoCode: "mg"
+  timeZoneIds: "Indian/Antananarivo"
+}
+countryMappings {
+  isoCode: "mh"
+  timeZoneIds: "Pacific/Majuro"
+  timeZoneLinks {
+    alternativeId: "Kwajalein"
+    preferredId: "Pacific/Kwajalein"
+  }
+  timeZoneReplacements {
+    replacedId: "Pacific/Kwajalein"
+    replacementId: "Pacific/Majuro"
+    fromMillis: 745934400000
+  }
+}
+countryMappings {
+  isoCode: "mk"
+  timeZoneIds: "Europe/Skopje"
+}
+countryMappings {
+  isoCode: "ml"
+  timeZoneIds: "Africa/Bamako"
+}
+countryMappings {
+  isoCode: "mm"
+  timeZoneIds: "Asia/Yangon"
+  timeZoneLinks {
+    alternativeId: "Asia/Rangoon"
+    preferredId: "Asia/Yangon"
+  }
+}
+countryMappings {
+  isoCode: "mn"
+  timeZoneIds: "Asia/Choibalsan"
+  timeZoneIds: "Asia/Ulaanbaatar"
+  timeZoneIds: "Asia/Hovd"
+  timeZoneLinks {
+    alternativeId: "Asia/Ulan_Bator"
+    preferredId: "Asia/Ulaanbaatar"
+  }
+}
+countryMappings {
+  isoCode: "mo"
+  timeZoneIds: "Asia/Macau"
+  timeZoneLinks {
+    alternativeId: "Asia/Macao"
+    preferredId: "Asia/Macau"
+  }
+}
+countryMappings {
+  isoCode: "mp"
+  timeZoneIds: "Pacific/Saipan"
+}
+countryMappings {
+  isoCode: "mq"
+  timeZoneIds: "America/Martinique"
+}
+countryMappings {
+  isoCode: "mr"
+  timeZoneIds: "Africa/Nouakchott"
+}
+countryMappings {
+  isoCode: "ms"
+  timeZoneIds: "America/Montserrat"
+}
+countryMappings {
+  isoCode: "mt"
+  timeZoneIds: "Europe/Malta"
+}
+countryMappings {
+  isoCode: "mu"
+  timeZoneIds: "Indian/Mauritius"
+}
+countryMappings {
+  isoCode: "mv"
+  timeZoneIds: "Indian/Maldives"
+}
+countryMappings {
+  isoCode: "mw"
+  timeZoneIds: "Africa/Blantyre"
+}
+countryMappings {
+  isoCode: "mx"
+  timeZoneIds: "America/Mexico_City"
+  timeZoneIds: "America/Matamoros"
+  timeZoneIds: "America/Cancun"
+  timeZoneIds: "America/Chihuahua"
+  timeZoneIds: "America/Hermosillo"
+  timeZoneIds: "America/Ojinaga"
+  timeZoneIds: "America/Tijuana"
+  timeZoneLinks {
+    alternativeId: "Mexico/General"
+    preferredId: "America/Mexico_City"
+  }
+  timeZoneLinks {
+    alternativeId: "Mexico/BajaSur"
+    preferredId: "America/Mazatlan"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Ensenada"
+    preferredId: "America/Tijuana"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Santa_Isabel"
+    preferredId: "America/Tijuana"
+  }
+  timeZoneLinks {
+    alternativeId: "Mexico/BajaNorte"
+    preferredId: "America/Tijuana"
+  }
+  timeZoneReplacements {
+    replacedId: "America/Merida"
+    replacementId: "America/Mexico_City"
+    fromMillis: 407653200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Monterrey"
+    replacementId: "America/Mexico_City"
+    fromMillis: 594198000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Bahia_Banderas"
+    replacementId: "America/Mexico_City"
+    fromMillis: 1270371600000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Mazatlan"
+    replacementId: "America/Chihuahua"
+    fromMillis: 891766800000
+  }
+}
+countryMappings {
+  isoCode: "my"
+  timeZoneIds: "Asia/Kuala_Lumpur"
+  timeZoneReplacements {
+    replacedId: "Asia/Kuching"
+    replacementId: "Asia/Kuala_Lumpur"
+    fromMillis: 378664200000
+  }
+}
+countryMappings {
+  isoCode: "mz"
+  timeZoneIds: "Africa/Maputo"
+}
+countryMappings {
+  isoCode: "na"
+  timeZoneIds: "Africa/Windhoek"
+}
+countryMappings {
+  isoCode: "nc"
+  timeZoneIds: "Pacific/Noumea"
+}
+countryMappings {
+  isoCode: "ne"
+  timeZoneIds: "Africa/Niamey"
+}
+countryMappings {
+  isoCode: "nf"
+  timeZoneIds: "Pacific/Norfolk"
+}
+countryMappings {
+  isoCode: "ng"
+  timeZoneIds: "Africa/Lagos"
+}
+countryMappings {
+  isoCode: "ni"
+  timeZoneIds: "America/Managua"
+}
+countryMappings {
+  isoCode: "nl"
+  timeZoneIds: "Europe/Amsterdam"
+}
+countryMappings {
+  isoCode: "no"
+  timeZoneIds: "Europe/Oslo"
+  timeZoneLinks {
+    alternativeId: "Atlantic/Jan_Mayen"
+    preferredId: "Europe/Oslo"
+  }
+}
+countryMappings {
+  isoCode: "np"
+  timeZoneIds: "Asia/Kathmandu"
+  timeZoneLinks {
+    alternativeId: "Asia/Katmandu"
+    preferredId: "Asia/Kathmandu"
+  }
+}
+countryMappings {
+  isoCode: "nr"
+  timeZoneIds: "Pacific/Nauru"
+}
+countryMappings {
+  isoCode: "nu"
+  timeZoneIds: "Pacific/Niue"
+}
+countryMappings {
+  isoCode: "nz"
+  timeZoneIds: "Pacific/Auckland"
+  timeZoneIds: "Pacific/Chatham"
+  timeZoneLinks {
+    alternativeId: "Antarctica/South_Pole"
+    preferredId: "Pacific/Auckland"
+  }
+  timeZoneLinks {
+    alternativeId: "NZ"
+    preferredId: "Pacific/Auckland"
+  }
+  timeZoneLinks {
+    alternativeId: "NZ-CHAT"
+    preferredId: "Pacific/Chatham"
+  }
+}
+countryMappings {
+  isoCode: "om"
+  timeZoneIds: "Asia/Muscat"
+}
+countryMappings {
+  isoCode: "pa"
+  timeZoneIds: "America/Panama"
+}
+countryMappings {
+  isoCode: "pe"
+  timeZoneIds: "America/Lima"
+}
+countryMappings {
+  isoCode: "pf"
+  timeZoneIds: "Pacific/Gambier"
+  timeZoneIds: "Pacific/Marquesas"
+  timeZoneIds: "Pacific/Tahiti"
+}
+countryMappings {
+  isoCode: "pg"
+  timeZoneIds: "Pacific/Port_Moresby"
+  timeZoneIds: "Pacific/Bougainville"
+}
+countryMappings {
+  isoCode: "ph"
+  timeZoneIds: "Asia/Manila"
+}
+countryMappings {
+  isoCode: "pk"
+  timeZoneIds: "Asia/Karachi"
+}
+countryMappings {
+  isoCode: "pl"
+  timeZoneIds: "Europe/Warsaw"
+  timeZoneLinks {
+    alternativeId: "Poland"
+    preferredId: "Europe/Warsaw"
+  }
+}
+countryMappings {
+  isoCode: "pm"
+  timeZoneIds: "America/Miquelon"
+}
+countryMappings {
+  isoCode: "pn"
+  timeZoneIds: "Pacific/Pitcairn"
+}
+countryMappings {
+  isoCode: "pr"
+  timeZoneIds: "America/Puerto_Rico"
+}
+countryMappings {
+  isoCode: "ps"
+  timeZoneIds: "Asia/Hebron"
+  timeZoneReplacements {
+    replacedId: "Asia/Gaza"
+    replacementId: "Asia/Hebron"
+    fromMillis: 1317330000000
+  }
+}
+countryMappings {
+  isoCode: "pt"
+  timeZoneIds: "Europe/Lisbon"
+  timeZoneIds: "Atlantic/Azores"
+  timeZoneLinks {
+    alternativeId: "Portugal"
+    preferredId: "Europe/Lisbon"
+  }
+  timeZoneReplacements {
+    replacedId: "Atlantic/Madeira"
+    replacementId: "Europe/Lisbon"
+    fromMillis: 828234000000
+  }
+}
+countryMappings {
+  isoCode: "pw"
+  timeZoneIds: "Pacific/Palau"
+}
+countryMappings {
+  isoCode: "py"
+  timeZoneIds: "America/Asuncion"
+}
+countryMappings {
+  isoCode: "qa"
+  timeZoneIds: "Asia/Qatar"
+}
+countryMappings {
+  isoCode: "re"
+  timeZoneIds: "Indian/Reunion"
+}
+countryMappings {
+  isoCode: "ro"
+  timeZoneIds: "Europe/Bucharest"
+}
+countryMappings {
+  isoCode: "rs"
+  timeZoneIds: "Europe/Belgrade"
+}
+countryMappings {
+  isoCode: "ru"
+  timeZoneIds: "Asia/Kamchatka"
+  timeZoneIds: "Asia/Anadyr"
+  timeZoneIds: "Asia/Magadan"
+  timeZoneIds: "Asia/Sakhalin"
+  timeZoneIds: "Asia/Srednekolymsk"
+  timeZoneIds: "Asia/Vladivostok"
+  timeZoneIds: "Asia/Chita"
+  timeZoneIds: "Asia/Irkutsk"
+  timeZoneIds: "Asia/Krasnoyarsk"
+  timeZoneIds: "Asia/Novosibirsk"
+  timeZoneIds: "Asia/Barnaul"
+  timeZoneIds: "Asia/Omsk"
+  timeZoneIds: "Asia/Yekaterinburg"
+  timeZoneIds: "Europe/Samara"
+  timeZoneIds: "Europe/Saratov"
+  timeZoneIds: "Europe/Volgograd"
+  timeZoneIds: "Europe/Moscow"
+  timeZoneIds: "Europe/Kirov"
+  timeZoneIds: "Europe/Kaliningrad"
+  timeZoneLinks {
+    alternativeId: "W-SU"
+    preferredId: "Europe/Moscow"
+  }
+  timeZoneReplacements {
+    replacedId: "Asia/Ust-Nera"
+    replacementId: "Asia/Vladivostok"
+    fromMillis: 1315828800000
+  }
+  timeZoneReplacements {
+    replacedId: "Asia/Yakutsk"
+    replacementId: "Asia/Chita"
+    fromMillis: 1459015200000
+  }
+  timeZoneReplacements {
+    replacedId: "Asia/Khandyga"
+    replacementId: "Asia/Chita"
+    fromMillis: 1315832400000
+  }
+  timeZoneReplacements {
+    replacedId: "Asia/Novokuznetsk"
+    replacementId: "Asia/Krasnoyarsk"
+    fromMillis: 1459022400000
+  }
+  timeZoneReplacements {
+    replacedId: "Asia/Tomsk"
+    replacementId: "Asia/Barnaul"
+    fromMillis: 1464465600000
+  }
+  timeZoneReplacements {
+    replacedId: "Europe/Ulyanovsk"
+    replacementId: "Europe/Saratov"
+    fromMillis: 1480806000000
+  }
+  timeZoneReplacements {
+    replacedId: "Europe/Astrakhan"
+    replacementId: "Europe/Saratov"
+    fromMillis: 701823600000
+  }
+}
+countryMappings {
+  isoCode: "rw"
+  timeZoneIds: "Africa/Kigali"
+}
+countryMappings {
+  isoCode: "sa"
+  timeZoneIds: "Asia/Riyadh"
+}
+countryMappings {
+  isoCode: "sb"
+  timeZoneIds: "Pacific/Guadalcanal"
+}
+countryMappings {
+  isoCode: "sc"
+  timeZoneIds: "Indian/Mahe"
+}
+countryMappings {
+  isoCode: "sd"
+  timeZoneIds: "Africa/Khartoum"
+}
+countryMappings {
+  isoCode: "se"
+  timeZoneIds: "Europe/Stockholm"
+}
+countryMappings {
+  isoCode: "sg"
+  timeZoneIds: "Asia/Singapore"
+  timeZoneLinks {
+    alternativeId: "Singapore"
+    preferredId: "Asia/Singapore"
+  }
+}
+countryMappings {
+  isoCode: "sh"
+  timeZoneIds: "Atlantic/St_Helena"
+}
+countryMappings {
+  isoCode: "si"
+  timeZoneIds: "Europe/Ljubljana"
+}
+countryMappings {
+  isoCode: "sj"
+  timeZoneIds: "Arctic/Longyearbyen"
+}
+countryMappings {
+  isoCode: "sk"
+  timeZoneIds: "Europe/Bratislava"
+}
+countryMappings {
+  isoCode: "sl"
+  timeZoneIds: "Africa/Freetown"
+}
+countryMappings {
+  isoCode: "sm"
+  timeZoneIds: "Europe/San_Marino"
+}
+countryMappings {
+  isoCode: "sn"
+  timeZoneIds: "Africa/Dakar"
+}
+countryMappings {
+  isoCode: "so"
+  timeZoneIds: "Africa/Mogadishu"
+}
+countryMappings {
+  isoCode: "sr"
+  timeZoneIds: "America/Paramaribo"
+}
+countryMappings {
+  isoCode: "ss"
+  timeZoneIds: "Africa/Juba"
+}
+countryMappings {
+  isoCode: "st"
+  timeZoneIds: "Africa/Sao_Tome"
+}
+countryMappings {
+  isoCode: "sv"
+  timeZoneIds: "America/El_Salvador"
+}
+countryMappings {
+  isoCode: "sx"
+  timeZoneIds: "America/Lower_Princes"
+}
+countryMappings {
+  isoCode: "sy"
+  timeZoneIds: "Asia/Damascus"
+}
+countryMappings {
+  isoCode: "sz"
+  timeZoneIds: "Africa/Mbabane"
+}
+countryMappings {
+  isoCode: "tc"
+  timeZoneIds: "America/Grand_Turk"
+}
+countryMappings {
+  isoCode: "td"
+  timeZoneIds: "Africa/Ndjamena"
+}
+countryMappings {
+  isoCode: "tf"
+  timeZoneIds: "Indian/Kerguelen"
+}
+countryMappings {
+  isoCode: "tg"
+  timeZoneIds: "Africa/Lome"
+}
+countryMappings {
+  isoCode: "th"
+  timeZoneIds: "Asia/Bangkok"
+}
+countryMappings {
+  isoCode: "tj"
+  timeZoneIds: "Asia/Dushanbe"
+}
+countryMappings {
+  isoCode: "tk"
+  timeZoneIds: "Pacific/Fakaofo"
+}
+countryMappings {
+  isoCode: "tl"
+  timeZoneIds: "Asia/Dili"
+}
+countryMappings {
+  isoCode: "tm"
+  timeZoneIds: "Asia/Ashgabat"
+  timeZoneLinks {
+    alternativeId: "Asia/Ashkhabad"
+    preferredId: "Asia/Ashgabat"
+  }
+}
+countryMappings {
+  isoCode: "tn"
+  timeZoneIds: "Africa/Tunis"
+}
+countryMappings {
+  isoCode: "to"
+  timeZoneIds: "Pacific/Tongatapu"
+}
+countryMappings {
+  isoCode: "tr"
+  timeZoneIds: "Europe/Istanbul"
+  timeZoneLinks {
+    alternativeId: "Turkey"
+    preferredId: "Europe/Istanbul"
+  }
+}
+countryMappings {
+  isoCode: "tt"
+  timeZoneIds: "America/Port_of_Spain"
+  timeZoneLinks {
+    alternativeId: "America/Virgin"
+    preferredId: "America/Port_of_Spain"
+  }
+}
+countryMappings {
+  isoCode: "tv"
+  timeZoneIds: "Pacific/Funafuti"
+}
+countryMappings {
+  isoCode: "tw"
+  timeZoneIds: "Asia/Taipei"
+  timeZoneLinks {
+    alternativeId: "ROC"
+    preferredId: "Asia/Taipei"
+  }
+}
+countryMappings {
+  isoCode: "tz"
+  timeZoneIds: "Africa/Dar_es_Salaam"
+}
+countryMappings {
+  isoCode: "ua"
+  timeZoneIds: "Europe/Kiev"
+  timeZoneIds: "Europe/Simferopol"
+  timeZoneReplacements {
+    replacedId: "Europe/Zaporozhye"
+    replacementId: "Europe/Kiev"
+    fromMillis: 686102400000
+  }
+  timeZoneReplacements {
+    replacedId: "Europe/Uzhgorod"
+    replacementId: "Europe/Kiev"
+    fromMillis: 686091600000
+  }
+}
+countryMappings {
+  isoCode: "ug"
+  timeZoneIds: "Africa/Kampala"
+}
+countryMappings {
+  isoCode: "um"
+  timeZoneIds: "Pacific/Wake"
+  timeZoneIds: "Pacific/Midway"
+}
+countryMappings {
+  isoCode: "us"
+  timeZoneIds: "America/New_York"
+  timeZoneIds: "America/Chicago"
+  timeZoneIds: "America/Denver"
+  timeZoneIds: "America/Phoenix"
+  timeZoneIds: "America/Los_Angeles"
+  timeZoneIds: "America/Anchorage"
+  timeZoneIds: "Pacific/Honolulu"
+  timeZoneIds: "America/Adak"
+  timeZoneLinks {
+    alternativeId: "US/Eastern"
+    preferredId: "America/New_York"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Louisville"
+    preferredId: "America/Kentucky/Louisville"
+  }
+  timeZoneLinks {
+    alternativeId: "US/Michigan"
+    preferredId: "America/Detroit"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Fort_Wayne"
+    preferredId: "America/Indiana/Indianapolis"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Indianapolis"
+    preferredId: "America/Indiana/Indianapolis"
+  }
+  timeZoneLinks {
+    alternativeId: "US/East-Indiana"
+    preferredId: "America/Indiana/Indianapolis"
+  }
+  timeZoneLinks {
+    alternativeId: "US/Central"
+    preferredId: "America/Chicago"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Knox_IN"
+    preferredId: "America/Indiana/Knox"
+  }
+  timeZoneLinks {
+    alternativeId: "US/Indiana-Starke"
+    preferredId: "America/Indiana/Knox"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Shiprock"
+    preferredId: "America/Denver"
+  }
+  timeZoneLinks {
+    alternativeId: "Navajo"
+    preferredId: "America/Denver"
+  }
+  timeZoneLinks {
+    alternativeId: "US/Mountain"
+    preferredId: "America/Denver"
+  }
+  timeZoneLinks {
+    alternativeId: "US/Arizona"
+    preferredId: "America/Phoenix"
+  }
+  timeZoneLinks {
+    alternativeId: "US/Pacific"
+    preferredId: "America/Los_Angeles"
+  }
+  timeZoneLinks {
+    alternativeId: "US/Alaska"
+    preferredId: "America/Anchorage"
+  }
+  timeZoneLinks {
+    alternativeId: "Pacific/Johnston"
+    preferredId: "Pacific/Honolulu"
+  }
+  timeZoneLinks {
+    alternativeId: "US/Hawaii"
+    preferredId: "Pacific/Honolulu"
+  }
+  timeZoneLinks {
+    alternativeId: "America/Atka"
+    preferredId: "America/Adak"
+  }
+  timeZoneLinks {
+    alternativeId: "US/Aleutian"
+    preferredId: "America/Adak"
+  }
+  timeZoneReplacements {
+    replacedId: "America/Kentucky/Louisville"
+    replacementId: "America/New_York"
+    fromMillis: 152089200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Detroit"
+    replacementId: "America/New_York"
+    fromMillis: 167814000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Indiana/Indianapolis"
+    replacementId: "America/New_York"
+    fromMillis: 1130652000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Indiana/Vincennes"
+    replacementId: "America/New_York"
+    fromMillis: 1194159600000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Kentucky/Monticello"
+    replacementId: "America/New_York"
+    fromMillis: 972802800000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Indiana/Petersburg"
+    replacementId: "America/New_York"
+    fromMillis: 247042800000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Indiana/Winamac"
+    replacementId: "America/New_York"
+    fromMillis: 1173600000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Indiana/Vevay"
+    replacementId: "America/New_York"
+    fromMillis: 89186400000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Indiana/Marengo"
+    replacementId: "America/New_York"
+    fromMillis: 183535200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Menominee"
+    replacementId: "America/Chicago"
+    fromMillis: 104918400000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Indiana/Tell_City"
+    replacementId: "America/Chicago"
+    fromMillis: 1143964800000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Indiana/Knox"
+    replacementId: "America/Chicago"
+    fromMillis: 688546800000
+  }
+  timeZoneReplacements {
+    replacedId: "America/North_Dakota/Beulah"
+    replacementId: "America/Chicago"
+    fromMillis: 1289116800000
+  }
+  timeZoneReplacements {
+    replacedId: "America/North_Dakota/New_Salem"
+    replacementId: "America/Chicago"
+    fromMillis: 1067155200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/North_Dakota/Center"
+    replacementId: "America/Chicago"
+    fromMillis: 720000000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Boise"
+    replacementId: "America/Phoenix"
+    fromMillis: 129114000000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Juneau"
+    replacementId: "America/Anchorage"
+    fromMillis: 436359600000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Sitka"
+    replacementId: "America/Anchorage"
+    fromMillis: 341402400000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Nome"
+    replacementId: "America/Anchorage"
+    fromMillis: 436363200000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Metlakatla"
+    replacementId: "America/Anchorage"
+    fromMillis: 1547978400000
+  }
+  timeZoneReplacements {
+    replacedId: "America/Yakutat"
+    replacementId: "America/Anchorage"
+    fromMillis: 436356000000
+  }
+}
+countryMappings {
+  isoCode: "uy"
+  timeZoneIds: "America/Montevideo"
+}
+countryMappings {
+  isoCode: "uz"
+  timeZoneIds: "Asia/Tashkent"
+  timeZoneReplacements {
+    replacedId: "Asia/Samarkand"
+    replacementId: "Asia/Tashkent"
+    fromMillis: 670366800000
+  }
+}
+countryMappings {
+  isoCode: "va"
+  timeZoneIds: "Europe/Vatican"
+}
+countryMappings {
+  isoCode: "vc"
+  timeZoneIds: "America/St_Vincent"
+}
+countryMappings {
+  isoCode: "ve"
+  timeZoneIds: "America/Caracas"
+}
+countryMappings {
+  isoCode: "vg"
+  timeZoneIds: "America/Tortola"
+}
+countryMappings {
+  isoCode: "vi"
+  timeZoneIds: "America/St_Thomas"
+}
+countryMappings {
+  isoCode: "vn"
+  timeZoneIds: "Asia/Ho_Chi_Minh"
+  timeZoneLinks {
+    alternativeId: "Asia/Saigon"
+    preferredId: "Asia/Ho_Chi_Minh"
+  }
+}
+countryMappings {
+  isoCode: "vu"
+  timeZoneIds: "Pacific/Efate"
+}
+countryMappings {
+  isoCode: "wf"
+  timeZoneIds: "Pacific/Wallis"
+}
+countryMappings {
+  isoCode: "ws"
+  timeZoneIds: "Pacific/Apia"
+}
+countryMappings {
+  isoCode: "ye"
+  timeZoneIds: "Asia/Aden"
+}
+countryMappings {
+  isoCode: "yt"
+  timeZoneIds: "Indian/Mayotte"
+}
+countryMappings {
+  isoCode: "za"
+  timeZoneIds: "Africa/Johannesburg"
+}
+countryMappings {
+  isoCode: "zm"
+  timeZoneIds: "Africa/Lusaka"
+}
+countryMappings {
+  isoCode: "zw"
+  timeZoneIds: "Africa/Harare"
+}
diff --git a/output_data/android/tzlookup.xml b/output_data/android/tzlookup.xml
index 5240499..c703fad 100644
--- a/output_data/android/tzlookup.xml
+++ b/output_data/android/tzlookup.xml
@@ -41,38 +41,38 @@
    <id>Antarctica/Palmer</id>
   </country>
   <country code="ar" default="America/Argentina/Buenos_Aires" defaultBoost="y" everutc="n">
-   <id>America/Argentina/Buenos_Aires</id>
-   <id notafter="687931200000">America/Argentina/Cordoba</id>
-   <id notafter="1237082400000">America/Argentina/Mendoza</id>
-   <id notafter="1087099200000">America/Argentina/Tucuman</id>
-   <id notafter="1096171200000">America/Argentina/Salta</id>
-   <id notafter="1090728000000">America/Argentina/San_Juan</id>
-   <id notafter="687931200000">America/Argentina/Jujuy</id>
-   <id notafter="1087704000000">America/Argentina/Catamarca</id>
-   <id notafter="687931200000">America/Argentina/La_Rioja</id>
-   <id notafter="673588800000">America/Argentina/Rio_Gallegos</id>
-   <id notafter="1087704000000">America/Argentina/Ushuaia</id>
+   <id alts="America/Buenos_Aires">America/Argentina/Buenos_Aires</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires" alts="America/Cordoba,America/Rosario">America/Argentina/Cordoba</id>
+   <id notafter="1237082400000" repl="America/Argentina/Buenos_Aires" alts="America/Mendoza">America/Argentina/Mendoza</id>
+   <id notafter="1087099200000" repl="America/Argentina/Buenos_Aires">America/Argentina/Tucuman</id>
+   <id notafter="1096171200000" repl="America/Argentina/Buenos_Aires">America/Argentina/Salta</id>
+   <id notafter="1090728000000" repl="America/Argentina/Buenos_Aires">America/Argentina/San_Juan</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires" alts="America/Jujuy">America/Argentina/Jujuy</id>
+   <id notafter="1087704000000" repl="America/Argentina/Buenos_Aires" alts="America/Argentina/ComodRivadavia,America/Catamarca">America/Argentina/Catamarca</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires">America/Argentina/La_Rioja</id>
+   <id notafter="673588800000" repl="America/Argentina/Buenos_Aires">America/Argentina/Rio_Gallegos</id>
+   <id notafter="1087704000000" repl="America/Argentina/Buenos_Aires">America/Argentina/Ushuaia</id>
    <id>America/Argentina/San_Luis</id>
   </country>
   <country code="as" default="Pacific/Pago_Pago" everutc="n">
-   <id>Pacific/Pago_Pago</id>
+   <id alts="Pacific/Samoa,US/Samoa">Pacific/Pago_Pago</id>
   </country>
   <country code="at" default="Europe/Vienna" everutc="n">
    <id>Europe/Vienna</id>
   </country>
   <country code="au" default="Australia/Sydney" everutc="n">
-   <id>Australia/Sydney</id>
-   <id notafter="796147200000">Australia/Melbourne</id>
-   <id notafter="1193500800000">Australia/Hobart</id>
-   <id notafter="37728000000">Australia/Currie</id>
-   <id>Australia/Brisbane</id>
-   <id notafter="762883200000">Australia/Lindeman</id>
+   <id alts="Australia/ACT,Australia/Canberra,Australia/NSW">Australia/Sydney</id>
+   <id notafter="796147200000" repl="Australia/Sydney" alts="Australia/Victoria">Australia/Melbourne</id>
+   <id notafter="1193500800000" repl="Australia/Sydney" alts="Australia/Tasmania">Australia/Hobart</id>
+   <id notafter="37728000000" repl="Australia/Sydney">Australia/Currie</id>
+   <id alts="Australia/Queensland">Australia/Brisbane</id>
+   <id notafter="762883200000" repl="Australia/Brisbane">Australia/Lindeman</id>
    <id>Antarctica/Macquarie</id>
-   <id>Australia/Lord_Howe</id>
-   <id>Australia/Adelaide</id>
-   <id notafter="796149000000">Australia/Broken_Hill</id>
-   <id>Australia/Darwin</id>
-   <id>Australia/Perth</id>
+   <id alts="Australia/LHI">Australia/Lord_Howe</id>
+   <id alts="Australia/South">Australia/Adelaide</id>
+   <id notafter="796149000000" repl="Australia/Adelaide" alts="Australia/Yancowinna">Australia/Broken_Hill</id>
+   <id alts="Australia/North">Australia/Darwin</id>
+   <id alts="Australia/West">Australia/Perth</id>
    <id>Australia/Eucla</id>
   </country>
   <country code="aw" default="America/Aruba" everutc="n">
@@ -91,7 +91,7 @@
    <id>America/Barbados</id>
   </country>
   <country code="bd" default="Asia/Dhaka" everutc="n">
-   <id>Asia/Dhaka</id>
+   <id alts="Asia/Dacca">Asia/Dhaka</id>
   </country>
   <country code="be" default="Europe/Brussels" everutc="n">
    <id>Europe/Brussels</id>
@@ -127,28 +127,28 @@
    <id>America/Kralendijk</id>
   </country>
   <country code="br" default="America/Noronha" everutc="n">
-   <id>America/Noronha</id>
-   <id>America/Sao_Paulo</id>
-   <id notafter="1550368800000">America/Bahia</id>
-   <id notafter="1214280000000">America/Santarem</id>
-   <id notafter="1330221600000">America/Recife</id>
-   <id notafter="972180000000">America/Fortaleza</id>
-   <id notafter="1013911200000">America/Belem</id>
-   <id notafter="824004000000">America/Maceio</id>
-   <id notafter="1361066400000">America/Araguaina</id>
-   <id>America/Manaus</id>
-   <id notafter="1550372400000">America/Cuiaba</id>
-   <id notafter="1076814000000">America/Campo_Grande</id>
-   <id notafter="761713200000">America/Porto_Velho</id>
-   <id notafter="971578800000">America/Boa_Vista</id>
-   <id>America/Rio_Branco</id>
-   <id notafter="761716800000">America/Eirunepe</id>
+   <id alts="Brazil/DeNoronha">America/Noronha</id>
+   <id alts="Brazil/East">America/Sao_Paulo</id>
+   <id notafter="1550368800000" repl="America/Sao_Paulo">America/Bahia</id>
+   <id notafter="1214280000000" repl="America/Sao_Paulo">America/Santarem</id>
+   <id notafter="1330221600000" repl="America/Sao_Paulo">America/Recife</id>
+   <id notafter="972180000000" repl="America/Sao_Paulo">America/Fortaleza</id>
+   <id notafter="1013911200000" repl="America/Sao_Paulo">America/Belem</id>
+   <id notafter="824004000000" repl="America/Sao_Paulo">America/Maceio</id>
+   <id notafter="1361066400000" repl="America/Sao_Paulo">America/Araguaina</id>
+   <id alts="Brazil/West">America/Manaus</id>
+   <id notafter="1550372400000" repl="America/Manaus">America/Cuiaba</id>
+   <id notafter="1076814000000" repl="America/Manaus">America/Campo_Grande</id>
+   <id notafter="761713200000" repl="America/Manaus">America/Porto_Velho</id>
+   <id notafter="971578800000" repl="America/Manaus">America/Boa_Vista</id>
+   <id alts="America/Porto_Acre,Brazil/Acre">America/Rio_Branco</id>
+   <id notafter="761716800000" repl="America/Rio_Branco">America/Eirunepe</id>
   </country>
   <country code="bs" default="America/Nassau" everutc="n">
    <id>America/Nassau</id>
   </country>
   <country code="bt" default="Asia/Thimphu" everutc="n">
-   <id>Asia/Thimphu</id>
+   <id alts="Asia/Thimbu">Asia/Thimphu</id>
   </country>
   <country code="bw" default="Africa/Gaborone" everutc="n">
    <id>Africa/Gaborone</id>
@@ -160,34 +160,34 @@
    <id>America/Belize</id>
   </country>
   <country code="ca" default="America/Toronto" everutc="n">
-   <id>America/Toronto</id>
-   <id>America/Vancouver</id>
-   <id>America/Edmonton</id>
-   <id>America/Winnipeg</id>
-   <id>America/Halifax</id>
-   <id>America/St_Johns</id>
-   <id notafter="1162098000000">America/Moncton</id>
-   <id notafter="57733200000">America/Glace_Bay</id>
-   <id notafter="1299996000000">America/Goose_Bay</id>
+   <id alts="America/Montreal,Canada/Eastern">America/Toronto</id>
+   <id alts="Canada/Pacific">America/Vancouver</id>
+   <id alts="Canada/Mountain">America/Edmonton</id>
+   <id alts="Canada/Central">America/Winnipeg</id>
+   <id alts="Canada/Atlantic">America/Halifax</id>
+   <id alts="Canada/Newfoundland">America/St_Johns</id>
+   <id notafter="1162098000000" repl="America/Halifax">America/Moncton</id>
+   <id notafter="57733200000" repl="America/Halifax">America/Glace_Bay</id>
+   <id notafter="1299996000000" repl="America/Halifax">America/Goose_Bay</id>
    <id>America/Blanc-Sablon</id>
-   <id notafter="120636000000">America/Thunder_Bay</id>
-   <id notafter="972802800000">America/Iqaluit</id>
-   <id notafter="89186400000">America/Nipigon</id>
-   <id notafter="796806000000">America/Pangnirtung</id>
-   <id>America/Atikokan</id>
-   <id>America/Regina</id>
-   <id notafter="73472400000">America/Swift_Current</id>
-   <id notafter="1130659200000">America/Rankin_Inlet</id>
-   <id notafter="986112000000">America/Rainy_River</id>
-   <id notafter="1173600000000">America/Resolute</id>
-   <id notafter="309945600000">America/Yellowknife</id>
-   <id notafter="1583661600000">America/Dawson_Creek</id>
-   <id notafter="84013200000">America/Creston</id>
-   <id notafter="1425808800000">America/Fort_Nelson</id>
-   <id notafter="294228000000">America/Inuvik</id>
-   <id notafter="986115600000">America/Cambridge_Bay</id>
-   <id notafter="120646800000">America/Dawson</id>
-   <id>America/Whitehorse</id>
+   <id notafter="120636000000" repl="America/Toronto">America/Thunder_Bay</id>
+   <id notafter="972802800000" repl="America/Toronto">America/Iqaluit</id>
+   <id notafter="89186400000" repl="America/Toronto">America/Nipigon</id>
+   <id notafter="796806000000" repl="America/Toronto">America/Pangnirtung</id>
+   <id alts="America/Coral_Harbour">America/Atikokan</id>
+   <id alts="Canada/Saskatchewan">America/Regina</id>
+   <id notafter="73472400000" repl="America/Winnipeg">America/Swift_Current</id>
+   <id notafter="1130659200000" repl="America/Winnipeg">America/Rankin_Inlet</id>
+   <id notafter="986112000000" repl="America/Winnipeg">America/Rainy_River</id>
+   <id notafter="1173600000000" repl="America/Winnipeg">America/Resolute</id>
+   <id notafter="309945600000" repl="America/Edmonton">America/Yellowknife</id>
+   <id notafter="1583661600000" repl="America/Edmonton">America/Dawson_Creek</id>
+   <id notafter="84013200000" repl="America/Edmonton">America/Creston</id>
+   <id notafter="1425808800000" repl="America/Edmonton">America/Fort_Nelson</id>
+   <id notafter="294228000000" repl="America/Edmonton">America/Inuvik</id>
+   <id notafter="986115600000" repl="America/Edmonton">America/Cambridge_Bay</id>
+   <id notafter="120646800000" repl="America/Edmonton">America/Dawson</id>
+   <id alts="Canada/Yukon">America/Whitehorse</id>
   </country>
   <country code="cc" default="Indian/Cocos" everutc="n">
    <id>Indian/Cocos</id>
@@ -206,22 +206,22 @@
    <id>Europe/Zurich</id>
   </country>
   <country code="ci" default="Africa/Abidjan" everutc="y">
-   <id>Africa/Abidjan</id>
+   <id alts="Africa/Timbuktu">Africa/Abidjan</id>
   </country>
   <country code="ck" default="Pacific/Rarotonga" everutc="n">
    <id>Pacific/Rarotonga</id>
   </country>
   <country code="cl" default="America/Santiago" everutc="n">
    <id>America/Punta_Arenas</id>
-   <id>America/Santiago</id>
-   <id>Pacific/Easter</id>
+   <id alts="Chile/Continental">America/Santiago</id>
+   <id alts="Chile/EasterIsland">Pacific/Easter</id>
   </country>
   <country code="cm" default="Africa/Douala" everutc="n">
    <id>Africa/Douala</id>
   </country>
   <country code="cn" default="Asia/Shanghai" defaultBoost="y" everutc="n">
-   <id>Asia/Shanghai</id>
-   <id>Asia/Urumqi</id>
+   <id alts="Asia/Chongqing,Asia/Chungking,Asia/Harbin,PRC">Asia/Shanghai</id>
+   <id alts="Asia/Kashgar">Asia/Urumqi</id>
   </country>
   <country code="co" default="America/Bogota" everutc="n">
    <id>America/Bogota</id>
@@ -230,7 +230,7 @@
    <id>America/Costa_Rica</id>
   </country>
   <country code="cu" default="America/Havana" everutc="n">
-   <id>America/Havana</id>
+   <id alts="Cuba">America/Havana</id>
   </country>
   <country code="cv" default="Atlantic/Cape_Verde" everutc="n">
    <id>Atlantic/Cape_Verde</id>
@@ -250,7 +250,7 @@
   </country>
   <country code="de" default="Europe/Berlin" everutc="n">
    <id>Europe/Berlin</id>
-   <id notafter="338950800000">Europe/Busingen</id>
+   <id notafter="338950800000" repl="Europe/Berlin">Europe/Busingen</id>
   </country>
   <country code="dj" default="Africa/Djibouti" everutc="n">
    <id>Africa/Djibouti</id>
@@ -275,7 +275,7 @@
    <id>Europe/Tallinn</id>
   </country>
   <country code="eg" default="Africa/Cairo" everutc="n">
-   <id>Africa/Cairo</id>
+   <id alts="Egypt">Africa/Cairo</id>
   </country>
   <country code="eh" default="Africa/El_Aaiun" everutc="y">
    <id>Africa/El_Aaiun</id>
@@ -285,7 +285,7 @@
   </country>
   <country code="es" default="Europe/Madrid" everutc="y">
    <id>Europe/Madrid</id>
-   <id notafter="496803600000">Africa/Ceuta</id>
+   <id notafter="496803600000" repl="Europe/Madrid">Africa/Ceuta</id>
    <id>Atlantic/Canary</id>
   </country>
   <country code="et" default="Africa/Addis_Ababa" everutc="n">
@@ -301,12 +301,12 @@
    <id>Atlantic/Stanley</id>
   </country>
   <country code="fm" default="Pacific/Pohnpei" everutc="n">
-   <id>Pacific/Pohnpei</id>
+   <id alts="Pacific/Ponape">Pacific/Pohnpei</id>
    <id>Pacific/Kosrae</id>
-   <id>Pacific/Chuuk</id>
+   <id alts="Pacific/Truk,Pacific/Yap">Pacific/Chuuk</id>
   </country>
   <country code="fo" default="Atlantic/Faroe" everutc="y">
-   <id>Atlantic/Faroe</id>
+   <id alts="Atlantic/Faeroe">Atlantic/Faroe</id>
   </country>
   <country code="fr" default="Europe/Paris" everutc="n">
    <id>Europe/Paris</id>
@@ -315,7 +315,7 @@
    <id>Africa/Libreville</id>
   </country>
   <country code="gb" default="Europe/London" everutc="y">
-   <id>Europe/London</id>
+   <id alts="Europe/Belfast,GB,GB-Eire">Europe/London</id>
   </country>
   <country code="gd" default="America/Grenada" everutc="n">
    <id>America/Grenada</id>
@@ -338,7 +338,7 @@
   <country code="gl" default="America/Nuuk" everutc="y">
    <id>America/Danmarkshavn</id>
    <id>America/Scoresbysund</id>
-   <id>America/Nuuk</id>
+   <id alts="America/Godthab">America/Nuuk</id>
    <id>America/Thule</id>
   </country>
   <country code="gm" default="Africa/Banjul" everutc="y">
@@ -372,7 +372,7 @@
    <id>America/Guyana</id>
   </country>
   <country code="hk" default="Asia/Hong_Kong" everutc="n">
-   <id>Asia/Hong_Kong</id>
+   <id alts="Hongkong">Asia/Hong_Kong</id>
   </country>
   <country code="hn" default="America/Tegucigalpa" everutc="n">
    <id>America/Tegucigalpa</id>
@@ -388,21 +388,21 @@
   </country>
   <country code="id" default="Asia/Jakarta" everutc="n">
    <id>Asia/Jayapura</id>
-   <id>Asia/Makassar</id>
+   <id alts="Asia/Ujung_Pandang">Asia/Makassar</id>
    <id>Asia/Jakarta</id>
-   <id notafter="567964800000">Asia/Pontianak</id>
+   <id notafter="567964800000" repl="Asia/Jakarta">Asia/Pontianak</id>
   </country>
   <country code="ie" default="Europe/Dublin" everutc="y">
-   <id>Europe/Dublin</id>
+   <id alts="Eire">Europe/Dublin</id>
   </country>
   <country code="il" default="Asia/Jerusalem" everutc="n">
-   <id>Asia/Jerusalem</id>
+   <id alts="Asia/Tel_Aviv,Israel">Asia/Jerusalem</id>
   </country>
   <country code="im" default="Europe/Isle_of_Man" everutc="y">
    <id>Europe/Isle_of_Man</id>
   </country>
   <country code="in" default="Asia/Kolkata" everutc="n">
-   <id>Asia/Kolkata</id>
+   <id alts="Asia/Calcutta">Asia/Kolkata</id>
   </country>
   <country code="io" default="Indian/Chagos" everutc="n">
    <id>Indian/Chagos</id>
@@ -411,10 +411,10 @@
    <id>Asia/Baghdad</id>
   </country>
   <country code="ir" default="Asia/Tehran" everutc="n">
-   <id>Asia/Tehran</id>
+   <id alts="Iran">Asia/Tehran</id>
   </country>
   <country code="is" default="Atlantic/Reykjavik" everutc="y">
-   <id>Atlantic/Reykjavik</id>
+   <id alts="Iceland">Atlantic/Reykjavik</id>
   </country>
   <country code="it" default="Europe/Rome" everutc="n">
    <id>Europe/Rome</id>
@@ -423,16 +423,16 @@
    <id>Europe/Jersey</id>
   </country>
   <country code="jm" default="America/Jamaica" everutc="n">
-   <id>America/Jamaica</id>
+   <id alts="Jamaica">America/Jamaica</id>
   </country>
   <country code="jo" default="Asia/Amman" everutc="n">
    <id>Asia/Amman</id>
   </country>
   <country code="jp" default="Asia/Tokyo" everutc="n">
-   <id>Asia/Tokyo</id>
+   <id alts="Japan">Asia/Tokyo</id>
   </country>
   <country code="ke" default="Africa/Nairobi" everutc="n">
-   <id>Africa/Nairobi</id>
+   <id alts="Africa/Asmera">Africa/Nairobi</id>
   </country>
   <country code="kg" default="Asia/Bishkek" everutc="n">
    <id>Asia/Bishkek</id>
@@ -455,7 +455,7 @@
    <id>Asia/Pyongyang</id>
   </country>
   <country code="kr" default="Asia/Seoul" everutc="n">
-   <id>Asia/Seoul</id>
+   <id alts="ROK">Asia/Seoul</id>
   </country>
   <country code="kw" default="Asia/Kuwait" everutc="n">
    <id>Asia/Kuwait</id>
@@ -465,12 +465,12 @@
   </country>
   <country code="kz" default="Asia/Almaty" everutc="n">
    <id>Asia/Almaty</id>
-   <id notafter="1099170000000">Asia/Qostanay</id>
+   <id notafter="1099170000000" repl="Asia/Almaty">Asia/Qostanay</id>
    <id>Asia/Oral</id>
-   <id notafter="1099173600000">Asia/Aqtau</id>
-   <id notafter="1545328800000">Asia/Qyzylorda</id>
-   <id notafter="1545328800000">Asia/Aqtobe</id>
-   <id notafter="922572000000">Asia/Atyrau</id>
+   <id notafter="1099173600000" repl="Asia/Oral">Asia/Aqtau</id>
+   <id notafter="1545328800000" repl="Asia/Oral">Asia/Qyzylorda</id>
+   <id notafter="1545328800000" repl="Asia/Oral">Asia/Aqtobe</id>
+   <id notafter="922572000000" repl="Asia/Oral">Asia/Atyrau</id>
   </country>
   <country code="la" default="Asia/Vientiane" everutc="n">
    <id>Asia/Vientiane</id>
@@ -503,7 +503,7 @@
    <id>Europe/Riga</id>
   </country>
   <country code="ly" default="Africa/Tripoli" everutc="n">
-   <id>Africa/Tripoli</id>
+   <id alts="Libya">Africa/Tripoli</id>
   </country>
   <country code="ma" default="Africa/Casablanca" everutc="y">
    <id>Africa/Casablanca</id>
@@ -512,7 +512,7 @@
    <id>Europe/Monaco</id>
   </country>
   <country code="md" default="Europe/Chisinau" everutc="n">
-   <id>Europe/Chisinau</id>
+   <id alts="Europe/Tiraspol">Europe/Chisinau</id>
   </country>
   <country code="me" default="Europe/Podgorica" everutc="n">
    <id>Europe/Podgorica</id>
@@ -525,7 +525,7 @@
   </country>
   <country code="mh" default="Pacific/Majuro" everutc="n">
    <id>Pacific/Majuro</id>
-   <id notafter="745934400000">Pacific/Kwajalein</id>
+   <id notafter="745934400000" repl="Pacific/Majuro" alts="Kwajalein">Pacific/Kwajalein</id>
   </country>
   <country code="mk" default="Europe/Skopje" everutc="n">
    <id>Europe/Skopje</id>
@@ -534,15 +534,15 @@
    <id>Africa/Bamako</id>
   </country>
   <country code="mm" default="Asia/Yangon" everutc="n">
-   <id>Asia/Yangon</id>
+   <id alts="Asia/Rangoon">Asia/Yangon</id>
   </country>
   <country code="mn" default="Asia/Ulaanbaatar" everutc="n">
    <id>Asia/Choibalsan</id>
-   <id>Asia/Ulaanbaatar</id>
+   <id alts="Asia/Ulan_Bator">Asia/Ulaanbaatar</id>
    <id>Asia/Hovd</id>
   </country>
   <country code="mo" default="Asia/Macau" everutc="n">
-   <id>Asia/Macau</id>
+   <id alts="Asia/Macao">Asia/Macau</id>
   </country>
   <country code="mp" default="Pacific/Saipan" everutc="n">
    <id>Pacific/Saipan</id>
@@ -569,21 +569,21 @@
    <id>Africa/Blantyre</id>
   </country>
   <country code="mx" default="America/Mexico_City" everutc="n">
-   <id>America/Mexico_City</id>
-   <id notafter="407653200000">America/Merida</id>
-   <id notafter="594198000000">America/Monterrey</id>
-   <id notafter="1270371600000">America/Bahia_Banderas</id>
+   <id alts="Mexico/General">America/Mexico_City</id>
+   <id notafter="407653200000" repl="America/Mexico_City">America/Merida</id>
+   <id notafter="594198000000" repl="America/Mexico_City">America/Monterrey</id>
+   <id notafter="1270371600000" repl="America/Mexico_City">America/Bahia_Banderas</id>
    <id>America/Matamoros</id>
    <id>America/Cancun</id>
    <id>America/Chihuahua</id>
-   <id notafter="891766800000">America/Mazatlan</id>
+   <id notafter="891766800000" repl="America/Chihuahua" alts="Mexico/BajaSur">America/Mazatlan</id>
    <id>America/Hermosillo</id>
    <id>America/Ojinaga</id>
-   <id>America/Tijuana</id>
+   <id alts="America/Ensenada,America/Santa_Isabel,Mexico/BajaNorte">America/Tijuana</id>
   </country>
   <country code="my" default="Asia/Kuala_Lumpur" everutc="n">
    <id>Asia/Kuala_Lumpur</id>
-   <id notafter="378664200000">Asia/Kuching</id>
+   <id notafter="378664200000" repl="Asia/Kuala_Lumpur">Asia/Kuching</id>
   </country>
   <country code="mz" default="Africa/Maputo" everutc="n">
    <id>Africa/Maputo</id>
@@ -610,10 +610,10 @@
    <id>Europe/Amsterdam</id>
   </country>
   <country code="no" default="Europe/Oslo" everutc="n">
-   <id>Europe/Oslo</id>
+   <id alts="Atlantic/Jan_Mayen">Europe/Oslo</id>
   </country>
   <country code="np" default="Asia/Kathmandu" everutc="n">
-   <id>Asia/Kathmandu</id>
+   <id alts="Asia/Katmandu">Asia/Kathmandu</id>
   </country>
   <country code="nr" default="Pacific/Nauru" everutc="n">
    <id>Pacific/Nauru</id>
@@ -622,8 +622,8 @@
    <id>Pacific/Niue</id>
   </country>
   <country code="nz" default="Pacific/Auckland" defaultBoost="y" everutc="n">
-   <id>Pacific/Auckland</id>
-   <id>Pacific/Chatham</id>
+   <id alts="Antarctica/South_Pole,NZ">Pacific/Auckland</id>
+   <id alts="NZ-CHAT">Pacific/Chatham</id>
   </country>
   <country code="om" default="Asia/Muscat" everutc="n">
    <id>Asia/Muscat</id>
@@ -650,7 +650,7 @@
    <id>Asia/Karachi</id>
   </country>
   <country code="pl" default="Europe/Warsaw" everutc="n">
-   <id>Europe/Warsaw</id>
+   <id alts="Poland">Europe/Warsaw</id>
   </country>
   <country code="pm" default="America/Miquelon" everutc="n">
    <id>America/Miquelon</id>
@@ -663,11 +663,11 @@
   </country>
   <country code="ps" default="Asia/Gaza" everutc="n">
    <id>Asia/Hebron</id>
-   <id notafter="1317330000000">Asia/Gaza</id>
+   <id notafter="1317330000000" repl="Asia/Hebron">Asia/Gaza</id>
   </country>
   <country code="pt" default="Europe/Lisbon" everutc="y">
-   <id>Europe/Lisbon</id>
-   <id notafter="828234000000">Atlantic/Madeira</id>
+   <id alts="Portugal">Europe/Lisbon</id>
+   <id notafter="828234000000" repl="Europe/Lisbon">Atlantic/Madeira</id>
    <id>Atlantic/Azores</id>
   </country>
   <country code="pw" default="Pacific/Palau" everutc="n">
@@ -695,24 +695,24 @@
    <id>Asia/Sakhalin</id>
    <id>Asia/Srednekolymsk</id>
    <id>Asia/Vladivostok</id>
-   <id notafter="1315828800000">Asia/Ust-Nera</id>
+   <id notafter="1315828800000" repl="Asia/Vladivostok">Asia/Ust-Nera</id>
    <id>Asia/Chita</id>
-   <id notafter="1459015200000">Asia/Yakutsk</id>
-   <id notafter="1315832400000">Asia/Khandyga</id>
+   <id notafter="1459015200000" repl="Asia/Chita">Asia/Yakutsk</id>
+   <id notafter="1315832400000" repl="Asia/Chita">Asia/Khandyga</id>
    <id>Asia/Irkutsk</id>
    <id>Asia/Krasnoyarsk</id>
-   <id notafter="1459022400000">Asia/Novokuznetsk</id>
+   <id notafter="1459022400000" repl="Asia/Krasnoyarsk">Asia/Novokuznetsk</id>
    <id>Asia/Novosibirsk</id>
    <id>Asia/Barnaul</id>
-   <id notafter="1464465600000">Asia/Tomsk</id>
+   <id notafter="1464465600000" repl="Asia/Barnaul">Asia/Tomsk</id>
    <id>Asia/Omsk</id>
    <id>Asia/Yekaterinburg</id>
    <id>Europe/Samara</id>
    <id>Europe/Saratov</id>
-   <id notafter="1480806000000">Europe/Ulyanovsk</id>
-   <id notafter="701823600000">Europe/Astrakhan</id>
+   <id notafter="1480806000000" repl="Europe/Saratov">Europe/Ulyanovsk</id>
+   <id notafter="701823600000" repl="Europe/Saratov">Europe/Astrakhan</id>
    <id>Europe/Volgograd</id>
-   <id>Europe/Moscow</id>
+   <id alts="W-SU">Europe/Moscow</id>
    <id>Europe/Kirov</id>
    <id>Europe/Kaliningrad</id>
   </country>
@@ -735,7 +735,7 @@
    <id>Europe/Stockholm</id>
   </country>
   <country code="sg" default="Asia/Singapore" everutc="n">
-   <id>Asia/Singapore</id>
+   <id alts="Singapore">Asia/Singapore</id>
   </country>
   <country code="sh" default="Atlantic/St_Helena" everutc="y">
    <id>Atlantic/St_Helena</id>
@@ -807,7 +807,7 @@
    <id>Asia/Dili</id>
   </country>
   <country code="tm" default="Asia/Ashgabat" everutc="n">
-   <id>Asia/Ashgabat</id>
+   <id alts="Asia/Ashkhabad">Asia/Ashgabat</id>
   </country>
   <country code="tn" default="Africa/Tunis" everutc="n">
    <id>Africa/Tunis</id>
@@ -816,24 +816,24 @@
    <id>Pacific/Tongatapu</id>
   </country>
   <country code="tr" default="Europe/Istanbul" everutc="n">
-   <id>Europe/Istanbul</id>
+   <id alts="Turkey">Europe/Istanbul</id>
   </country>
   <country code="tt" default="America/Port_of_Spain" everutc="n">
-   <id>America/Port_of_Spain</id>
+   <id alts="America/Virgin">America/Port_of_Spain</id>
   </country>
   <country code="tv" default="Pacific/Funafuti" everutc="n">
    <id>Pacific/Funafuti</id>
   </country>
   <country code="tw" default="Asia/Taipei" everutc="n">
-   <id>Asia/Taipei</id>
+   <id alts="ROC">Asia/Taipei</id>
   </country>
   <country code="tz" default="Africa/Dar_es_Salaam" everutc="n">
    <id>Africa/Dar_es_Salaam</id>
   </country>
   <country code="ua" default="Europe/Kiev" everutc="n">
    <id>Europe/Kiev</id>
-   <id notafter="686102400000">Europe/Zaporozhye</id>
-   <id notafter="686091600000">Europe/Uzhgorod</id>
+   <id notafter="686102400000" repl="Europe/Kiev">Europe/Zaporozhye</id>
+   <id notafter="686091600000" repl="Europe/Kiev">Europe/Uzhgorod</id>
    <id picker="n">Europe/Simferopol</id>
   </country>
   <country code="ug" default="Africa/Kampala" everutc="n">
@@ -844,42 +844,42 @@
    <id>Pacific/Midway</id>
   </country>
   <country code="us" default="America/New_York" everutc="n">
-   <id>America/New_York</id>
-   <id notafter="152089200000">America/Kentucky/Louisville</id>
-   <id notafter="167814000000">America/Detroit</id>
-   <id notafter="1130652000000">America/Indiana/Indianapolis</id>
-   <id notafter="1194159600000">America/Indiana/Vincennes</id>
-   <id notafter="972802800000">America/Kentucky/Monticello</id>
-   <id notafter="247042800000">America/Indiana/Petersburg</id>
-   <id notafter="1173600000000">America/Indiana/Winamac</id>
-   <id notafter="89186400000">America/Indiana/Vevay</id>
-   <id notafter="183535200000">America/Indiana/Marengo</id>
-   <id>America/Chicago</id>
-   <id notafter="104918400000">America/Menominee</id>
-   <id notafter="1143964800000">America/Indiana/Tell_City</id>
-   <id notafter="688546800000">America/Indiana/Knox</id>
-   <id notafter="1289116800000">America/North_Dakota/Beulah</id>
-   <id notafter="1067155200000">America/North_Dakota/New_Salem</id>
-   <id notafter="720000000000">America/North_Dakota/Center</id>
-   <id>America/Denver</id>
-   <id>America/Phoenix</id>
-   <id notafter="129114000000">America/Boise</id>
-   <id>America/Los_Angeles</id>
-   <id>America/Anchorage</id>
-   <id notafter="436359600000">America/Juneau</id>
-   <id notafter="341402400000">America/Sitka</id>
-   <id notafter="436363200000">America/Nome</id>
-   <id notafter="1547978400000">America/Metlakatla</id>
-   <id notafter="436356000000">America/Yakutat</id>
-   <id>Pacific/Honolulu</id>
-   <id>America/Adak</id>
+   <id alts="US/Eastern">America/New_York</id>
+   <id notafter="152089200000" repl="America/New_York" alts="America/Louisville">America/Kentucky/Louisville</id>
+   <id notafter="167814000000" repl="America/New_York" alts="US/Michigan">America/Detroit</id>
+   <id notafter="1130652000000" repl="America/New_York" alts="America/Fort_Wayne,America/Indianapolis,US/East-Indiana">America/Indiana/Indianapolis</id>
+   <id notafter="1194159600000" repl="America/New_York">America/Indiana/Vincennes</id>
+   <id notafter="972802800000" repl="America/New_York">America/Kentucky/Monticello</id>
+   <id notafter="247042800000" repl="America/New_York">America/Indiana/Petersburg</id>
+   <id notafter="1173600000000" repl="America/New_York">America/Indiana/Winamac</id>
+   <id notafter="89186400000" repl="America/New_York">America/Indiana/Vevay</id>
+   <id notafter="183535200000" repl="America/New_York">America/Indiana/Marengo</id>
+   <id alts="US/Central">America/Chicago</id>
+   <id notafter="104918400000" repl="America/Chicago">America/Menominee</id>
+   <id notafter="1143964800000" repl="America/Chicago">America/Indiana/Tell_City</id>
+   <id notafter="688546800000" repl="America/Chicago" alts="America/Knox_IN,US/Indiana-Starke">America/Indiana/Knox</id>
+   <id notafter="1289116800000" repl="America/Chicago">America/North_Dakota/Beulah</id>
+   <id notafter="1067155200000" repl="America/Chicago">America/North_Dakota/New_Salem</id>
+   <id notafter="720000000000" repl="America/Chicago">America/North_Dakota/Center</id>
+   <id alts="America/Shiprock,Navajo,US/Mountain">America/Denver</id>
+   <id alts="US/Arizona">America/Phoenix</id>
+   <id notafter="129114000000" repl="America/Phoenix">America/Boise</id>
+   <id alts="US/Pacific">America/Los_Angeles</id>
+   <id alts="US/Alaska">America/Anchorage</id>
+   <id notafter="436359600000" repl="America/Anchorage">America/Juneau</id>
+   <id notafter="341402400000" repl="America/Anchorage">America/Sitka</id>
+   <id notafter="436363200000" repl="America/Anchorage">America/Nome</id>
+   <id notafter="1547978400000" repl="America/Anchorage">America/Metlakatla</id>
+   <id notafter="436356000000" repl="America/Anchorage">America/Yakutat</id>
+   <id alts="Pacific/Johnston,US/Hawaii">Pacific/Honolulu</id>
+   <id alts="America/Atka,US/Aleutian">America/Adak</id>
   </country>
   <country code="uy" default="America/Montevideo" everutc="n">
    <id>America/Montevideo</id>
   </country>
   <country code="uz" default="Asia/Tashkent" everutc="n">
    <id>Asia/Tashkent</id>
-   <id notafter="670366800000">Asia/Samarkand</id>
+   <id notafter="670366800000" repl="Asia/Tashkent">Asia/Samarkand</id>
   </country>
   <country code="va" default="Europe/Vatican" everutc="n">
    <id>Europe/Vatican</id>
@@ -897,7 +897,7 @@
    <id>America/St_Thomas</id>
   </country>
   <country code="vn" default="Asia/Ho_Chi_Minh" everutc="n">
-   <id>Asia/Ho_Chi_Minh</id>
+   <id alts="Asia/Saigon">Asia/Ho_Chi_Minh</id>
   </country>
   <country code="vu" default="Pacific/Efate" everutc="n">
    <id>Pacific/Efate</id>
diff --git a/output_data/distro/distro.zip b/output_data/distro/distro.zip
index 17d8c07..c12abf1 100644
--- a/output_data/distro/distro.zip
+++ b/output_data/distro/distro.zip
Binary files differ
diff --git a/output_data/iana/tzdata b/output_data/iana/tzdata
index 301e264..422f03a 100644
--- a/output_data/iana/tzdata
+++ b/output_data/iana/tzdata
Binary files differ
diff --git a/output_data/version/tz_version b/output_data/version/tz_version
index 530048f..4240de7 100644
--- a/output_data/version/tz_version
+++ b/output_data/version/tz_version
@@ -1 +1 @@
-004.001|2020a|001
\ No newline at end of file
+005.001|2020a|001
\ No newline at end of file
diff --git a/testing/data/test1/output_data/android/tzlookup.xml b/testing/data/test1/output_data/android/tzlookup.xml
index 6297544..8906877 100644
--- a/testing/data/test1/output_data/android/tzlookup.xml
+++ b/testing/data/test1/output_data/android/tzlookup.xml
@@ -41,38 +41,38 @@
    <id>Antarctica/Palmer</id>
   </country>
   <country code="ar" default="America/Argentina/Buenos_Aires" defaultBoost="y" everutc="n">
-   <id>America/Argentina/Buenos_Aires</id>
-   <id notafter="687931200000">America/Argentina/Cordoba</id>
-   <id notafter="1237082400000">America/Argentina/Mendoza</id>
-   <id notafter="1087099200000">America/Argentina/Tucuman</id>
-   <id notafter="1096171200000">America/Argentina/Salta</id>
-   <id notafter="1090728000000">America/Argentina/San_Juan</id>
-   <id notafter="687931200000">America/Argentina/Jujuy</id>
-   <id notafter="1087704000000">America/Argentina/Catamarca</id>
-   <id notafter="687931200000">America/Argentina/La_Rioja</id>
-   <id notafter="673588800000">America/Argentina/Rio_Gallegos</id>
-   <id notafter="1087704000000">America/Argentina/Ushuaia</id>
+   <id alts="America/Buenos_Aires">America/Argentina/Buenos_Aires</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires" alts="America/Cordoba,America/Rosario">America/Argentina/Cordoba</id>
+   <id notafter="1237082400000" repl="America/Argentina/Buenos_Aires" alts="America/Mendoza">America/Argentina/Mendoza</id>
+   <id notafter="1087099200000" repl="America/Argentina/Buenos_Aires">America/Argentina/Tucuman</id>
+   <id notafter="1096171200000" repl="America/Argentina/Buenos_Aires">America/Argentina/Salta</id>
+   <id notafter="1090728000000" repl="America/Argentina/Buenos_Aires">America/Argentina/San_Juan</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires" alts="America/Jujuy">America/Argentina/Jujuy</id>
+   <id notafter="1087704000000" repl="America/Argentina/Buenos_Aires" alts="America/Argentina/ComodRivadavia,America/Catamarca">America/Argentina/Catamarca</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires">America/Argentina/La_Rioja</id>
+   <id notafter="673588800000" repl="America/Argentina/Buenos_Aires">America/Argentina/Rio_Gallegos</id>
+   <id notafter="1087704000000" repl="America/Argentina/Buenos_Aires">America/Argentina/Ushuaia</id>
    <id>America/Argentina/San_Luis</id>
   </country>
   <country code="as" default="Pacific/Pago_Pago" everutc="n">
-   <id>Pacific/Pago_Pago</id>
+   <id alts="Pacific/Samoa,US/Samoa">Pacific/Pago_Pago</id>
   </country>
   <country code="at" default="Europe/Vienna" everutc="n">
    <id>Europe/Vienna</id>
   </country>
   <country code="au" default="Australia/Sydney" everutc="n">
-   <id>Australia/Sydney</id>
-   <id notafter="796147200000">Australia/Melbourne</id>
-   <id notafter="1193500800000">Australia/Hobart</id>
-   <id notafter="37728000000">Australia/Currie</id>
-   <id>Australia/Brisbane</id>
-   <id notafter="762883200000">Australia/Lindeman</id>
+   <id alts="Australia/ACT,Australia/Canberra,Australia/NSW">Australia/Sydney</id>
+   <id notafter="796147200000" repl="Australia/Sydney" alts="Australia/Victoria">Australia/Melbourne</id>
+   <id notafter="1193500800000" repl="Australia/Sydney" alts="Australia/Tasmania">Australia/Hobart</id>
+   <id notafter="37728000000" repl="Australia/Sydney">Australia/Currie</id>
+   <id alts="Australia/Queensland">Australia/Brisbane</id>
+   <id notafter="762883200000" repl="Australia/Brisbane">Australia/Lindeman</id>
    <id>Antarctica/Macquarie</id>
-   <id>Australia/Lord_Howe</id>
-   <id>Australia/Adelaide</id>
-   <id notafter="796149000000">Australia/Broken_Hill</id>
-   <id>Australia/Darwin</id>
-   <id>Australia/Perth</id>
+   <id alts="Australia/LHI">Australia/Lord_Howe</id>
+   <id alts="Australia/South">Australia/Adelaide</id>
+   <id notafter="796149000000" repl="Australia/Adelaide" alts="Australia/Yancowinna">Australia/Broken_Hill</id>
+   <id alts="Australia/North">Australia/Darwin</id>
+   <id alts="Australia/West">Australia/Perth</id>
    <id>Australia/Eucla</id>
   </country>
   <country code="aw" default="America/Aruba" everutc="n">
@@ -91,7 +91,7 @@
    <id>America/Barbados</id>
   </country>
   <country code="bd" default="Asia/Dhaka" everutc="n">
-   <id>Asia/Dhaka</id>
+   <id alts="Asia/Dacca">Asia/Dhaka</id>
   </country>
   <country code="be" default="Europe/Brussels" everutc="n">
    <id>Europe/Brussels</id>
@@ -127,28 +127,28 @@
    <id>America/Kralendijk</id>
   </country>
   <country code="br" default="America/Noronha" everutc="n">
-   <id>America/Noronha</id>
-   <id>America/Sao_Paulo</id>
-   <id notafter="1550368800000">America/Bahia</id>
-   <id notafter="1214280000000">America/Santarem</id>
-   <id notafter="1330221600000">America/Recife</id>
-   <id notafter="972180000000">America/Fortaleza</id>
-   <id notafter="1013911200000">America/Belem</id>
-   <id notafter="824004000000">America/Maceio</id>
-   <id notafter="1361066400000">America/Araguaina</id>
-   <id>America/Manaus</id>
-   <id notafter="1550372400000">America/Cuiaba</id>
-   <id notafter="1076814000000">America/Campo_Grande</id>
-   <id notafter="761713200000">America/Porto_Velho</id>
-   <id notafter="971578800000">America/Boa_Vista</id>
-   <id>America/Rio_Branco</id>
-   <id notafter="761716800000">America/Eirunepe</id>
+   <id alts="Brazil/DeNoronha">America/Noronha</id>
+   <id alts="Brazil/East">America/Sao_Paulo</id>
+   <id notafter="1550368800000" repl="America/Sao_Paulo">America/Bahia</id>
+   <id notafter="1214280000000" repl="America/Sao_Paulo">America/Santarem</id>
+   <id notafter="1330221600000" repl="America/Sao_Paulo">America/Recife</id>
+   <id notafter="972180000000" repl="America/Sao_Paulo">America/Fortaleza</id>
+   <id notafter="1013911200000" repl="America/Sao_Paulo">America/Belem</id>
+   <id notafter="824004000000" repl="America/Sao_Paulo">America/Maceio</id>
+   <id notafter="1361066400000" repl="America/Sao_Paulo">America/Araguaina</id>
+   <id alts="Brazil/West">America/Manaus</id>
+   <id notafter="1550372400000" repl="America/Manaus">America/Cuiaba</id>
+   <id notafter="1076814000000" repl="America/Manaus">America/Campo_Grande</id>
+   <id notafter="761713200000" repl="America/Manaus">America/Porto_Velho</id>
+   <id notafter="971578800000" repl="America/Manaus">America/Boa_Vista</id>
+   <id alts="America/Porto_Acre,Brazil/Acre">America/Rio_Branco</id>
+   <id notafter="761716800000" repl="America/Rio_Branco">America/Eirunepe</id>
   </country>
   <country code="bs" default="America/Nassau" everutc="n">
    <id>America/Nassau</id>
   </country>
   <country code="bt" default="Asia/Thimphu" everutc="n">
-   <id>Asia/Thimphu</id>
+   <id alts="Asia/Thimbu">Asia/Thimphu</id>
   </country>
   <country code="bw" default="Africa/Gaborone" everutc="n">
    <id>Africa/Gaborone</id>
@@ -160,34 +160,34 @@
    <id>America/Belize</id>
   </country>
   <country code="ca" default="America/Toronto" everutc="n">
-   <id>America/Toronto</id>
-   <id>America/Vancouver</id>
-   <id>America/Edmonton</id>
-   <id>America/Winnipeg</id>
-   <id>America/Halifax</id>
-   <id>America/St_Johns</id>
-   <id notafter="1162098000000">America/Moncton</id>
-   <id notafter="57733200000">America/Glace_Bay</id>
-   <id notafter="1299996000000">America/Goose_Bay</id>
+   <id alts="America/Montreal,Canada/Eastern">America/Toronto</id>
+   <id alts="Canada/Pacific">America/Vancouver</id>
+   <id alts="Canada/Mountain">America/Edmonton</id>
+   <id alts="Canada/Central">America/Winnipeg</id>
+   <id alts="Canada/Atlantic">America/Halifax</id>
+   <id alts="Canada/Newfoundland">America/St_Johns</id>
+   <id notafter="1162098000000" repl="America/Halifax">America/Moncton</id>
+   <id notafter="57733200000" repl="America/Halifax">America/Glace_Bay</id>
+   <id notafter="1299996000000" repl="America/Halifax">America/Goose_Bay</id>
    <id>America/Blanc-Sablon</id>
-   <id notafter="120636000000">America/Thunder_Bay</id>
-   <id notafter="972802800000">America/Iqaluit</id>
-   <id notafter="89186400000">America/Nipigon</id>
-   <id notafter="796806000000">America/Pangnirtung</id>
-   <id>America/Atikokan</id>
-   <id>America/Regina</id>
-   <id notafter="73472400000">America/Swift_Current</id>
-   <id notafter="1130659200000">America/Rankin_Inlet</id>
-   <id notafter="986112000000">America/Rainy_River</id>
-   <id notafter="1173600000000">America/Resolute</id>
-   <id notafter="309945600000">America/Yellowknife</id>
-   <id notafter="1583661600000">America/Dawson_Creek</id>
-   <id notafter="84013200000">America/Creston</id>
-   <id notafter="1425808800000">America/Fort_Nelson</id>
-   <id notafter="294228000000">America/Inuvik</id>
-   <id notafter="986115600000">America/Cambridge_Bay</id>
-   <id notafter="120646800000">America/Dawson</id>
-   <id>America/Whitehorse</id>
+   <id notafter="120636000000" repl="America/Toronto">America/Thunder_Bay</id>
+   <id notafter="972802800000" repl="America/Toronto">America/Iqaluit</id>
+   <id notafter="89186400000" repl="America/Toronto">America/Nipigon</id>
+   <id notafter="796806000000" repl="America/Toronto">America/Pangnirtung</id>
+   <id alts="America/Coral_Harbour">America/Atikokan</id>
+   <id alts="Canada/Saskatchewan">America/Regina</id>
+   <id notafter="73472400000" repl="America/Winnipeg">America/Swift_Current</id>
+   <id notafter="1130659200000" repl="America/Winnipeg">America/Rankin_Inlet</id>
+   <id notafter="986112000000" repl="America/Winnipeg">America/Rainy_River</id>
+   <id notafter="1173600000000" repl="America/Winnipeg">America/Resolute</id>
+   <id notafter="309945600000" repl="America/Edmonton">America/Yellowknife</id>
+   <id notafter="1583661600000" repl="America/Edmonton">America/Dawson_Creek</id>
+   <id notafter="84013200000" repl="America/Edmonton">America/Creston</id>
+   <id notafter="1425808800000" repl="America/Edmonton">America/Fort_Nelson</id>
+   <id notafter="294228000000" repl="America/Edmonton">America/Inuvik</id>
+   <id notafter="986115600000" repl="America/Edmonton">America/Cambridge_Bay</id>
+   <id notafter="120646800000" repl="America/Edmonton">America/Dawson</id>
+   <id alts="Canada/Yukon">America/Whitehorse</id>
   </country>
   <country code="cc" default="Indian/Cocos" everutc="n">
    <id>Indian/Cocos</id>
@@ -206,22 +206,22 @@
    <id>Europe/Zurich</id>
   </country>
   <country code="ci" default="Africa/Abidjan" everutc="y">
-   <id>Africa/Abidjan</id>
+   <id alts="Africa/Timbuktu">Africa/Abidjan</id>
   </country>
   <country code="ck" default="Pacific/Rarotonga" everutc="n">
    <id>Pacific/Rarotonga</id>
   </country>
   <country code="cl" default="America/Santiago" everutc="n">
    <id>America/Punta_Arenas</id>
-   <id>America/Santiago</id>
-   <id>Pacific/Easter</id>
+   <id alts="Chile/Continental">America/Santiago</id>
+   <id alts="Chile/EasterIsland">Pacific/Easter</id>
   </country>
   <country code="cm" default="Africa/Douala" everutc="n">
    <id>Africa/Douala</id>
   </country>
   <country code="cn" default="Asia/Shanghai" defaultBoost="y" everutc="n">
-   <id>Asia/Shanghai</id>
-   <id>Asia/Urumqi</id>
+   <id alts="Asia/Chongqing,Asia/Chungking,Asia/Harbin,PRC">Asia/Shanghai</id>
+   <id alts="Asia/Kashgar">Asia/Urumqi</id>
   </country>
   <country code="co" default="America/Bogota" everutc="n">
    <id>America/Bogota</id>
@@ -230,7 +230,7 @@
    <id>America/Costa_Rica</id>
   </country>
   <country code="cu" default="America/Havana" everutc="n">
-   <id>America/Havana</id>
+   <id alts="Cuba">America/Havana</id>
   </country>
   <country code="cv" default="Atlantic/Cape_Verde" everutc="n">
    <id>Atlantic/Cape_Verde</id>
@@ -250,7 +250,7 @@
   </country>
   <country code="de" default="Europe/Berlin" everutc="n">
    <id>Europe/Berlin</id>
-   <id notafter="338950800000">Europe/Busingen</id>
+   <id notafter="338950800000" repl="Europe/Berlin">Europe/Busingen</id>
   </country>
   <country code="dj" default="Africa/Djibouti" everutc="n">
    <id>Africa/Djibouti</id>
@@ -275,7 +275,7 @@
    <id>Europe/Tallinn</id>
   </country>
   <country code="eg" default="Africa/Cairo" everutc="n">
-   <id>Africa/Cairo</id>
+   <id alts="Egypt">Africa/Cairo</id>
   </country>
   <country code="eh" default="Africa/El_Aaiun" everutc="y">
    <id>Africa/El_Aaiun</id>
@@ -285,7 +285,7 @@
   </country>
   <country code="es" default="Europe/Madrid" everutc="y">
    <id>Europe/Madrid</id>
-   <id notafter="496803600000">Africa/Ceuta</id>
+   <id notafter="496803600000" repl="Europe/Madrid">Africa/Ceuta</id>
    <id>Atlantic/Canary</id>
   </country>
   <country code="et" default="Africa/Addis_Ababa" everutc="n">
@@ -301,12 +301,12 @@
    <id>Atlantic/Stanley</id>
   </country>
   <country code="fm" default="Pacific/Pohnpei" everutc="n">
-   <id>Pacific/Pohnpei</id>
+   <id alts="Pacific/Ponape">Pacific/Pohnpei</id>
    <id>Pacific/Kosrae</id>
-   <id>Pacific/Chuuk</id>
+   <id alts="Pacific/Truk,Pacific/Yap">Pacific/Chuuk</id>
   </country>
   <country code="fo" default="Atlantic/Faroe" everutc="y">
-   <id>Atlantic/Faroe</id>
+   <id alts="Atlantic/Faeroe">Atlantic/Faroe</id>
   </country>
   <country code="fr" default="Europe/Paris" everutc="n">
    <id>Europe/Paris</id>
@@ -315,7 +315,7 @@
    <id>Africa/Libreville</id>
   </country>
   <country code="gb" default="Europe/London" everutc="y">
-   <id>Europe/London</id>
+   <id alts="Europe/Belfast,GB,GB-Eire">Europe/London</id>
   </country>
   <country code="gd" default="America/Grenada" everutc="n">
    <id>America/Grenada</id>
@@ -338,7 +338,7 @@
   <country code="gl" default="America/Nuuk" everutc="y">
    <id>America/Danmarkshavn</id>
    <id>America/Scoresbysund</id>
-   <id>America/Nuuk</id>
+   <id alts="America/Godthab">America/Nuuk</id>
    <id>America/Thule</id>
   </country>
   <country code="gm" default="Africa/Banjul" everutc="y">
@@ -372,7 +372,7 @@
    <id>America/Guyana</id>
   </country>
   <country code="hk" default="Asia/Hong_Kong" everutc="n">
-   <id>Asia/Hong_Kong</id>
+   <id alts="Hongkong">Asia/Hong_Kong</id>
   </country>
   <country code="hn" default="America/Tegucigalpa" everutc="n">
    <id>America/Tegucigalpa</id>
@@ -388,21 +388,21 @@
   </country>
   <country code="id" default="Asia/Jakarta" everutc="n">
    <id>Asia/Jayapura</id>
-   <id>Asia/Makassar</id>
+   <id alts="Asia/Ujung_Pandang">Asia/Makassar</id>
    <id>Asia/Jakarta</id>
-   <id notafter="567964800000">Asia/Pontianak</id>
+   <id notafter="567964800000" repl="Asia/Jakarta">Asia/Pontianak</id>
   </country>
   <country code="ie" default="Europe/Dublin" everutc="y">
-   <id>Europe/Dublin</id>
+   <id alts="Eire">Europe/Dublin</id>
   </country>
   <country code="il" default="Asia/Jerusalem" everutc="n">
-   <id>Asia/Jerusalem</id>
+   <id alts="Asia/Tel_Aviv,Israel">Asia/Jerusalem</id>
   </country>
   <country code="im" default="Europe/Isle_of_Man" everutc="y">
    <id>Europe/Isle_of_Man</id>
   </country>
   <country code="in" default="Asia/Kolkata" everutc="n">
-   <id>Asia/Kolkata</id>
+   <id alts="Asia/Calcutta">Asia/Kolkata</id>
   </country>
   <country code="io" default="Indian/Chagos" everutc="n">
    <id>Indian/Chagos</id>
@@ -411,10 +411,10 @@
    <id>Asia/Baghdad</id>
   </country>
   <country code="ir" default="Asia/Tehran" everutc="n">
-   <id>Asia/Tehran</id>
+   <id alts="Iran">Asia/Tehran</id>
   </country>
   <country code="is" default="Atlantic/Reykjavik" everutc="y">
-   <id>Atlantic/Reykjavik</id>
+   <id alts="Iceland">Atlantic/Reykjavik</id>
   </country>
   <country code="it" default="Europe/Rome" everutc="n">
    <id>Europe/Rome</id>
@@ -423,16 +423,16 @@
    <id>Europe/Jersey</id>
   </country>
   <country code="jm" default="America/Jamaica" everutc="n">
-   <id>America/Jamaica</id>
+   <id alts="Jamaica">America/Jamaica</id>
   </country>
   <country code="jo" default="Asia/Amman" everutc="n">
    <id>Asia/Amman</id>
   </country>
   <country code="jp" default="Asia/Tokyo" everutc="n">
-   <id>Asia/Tokyo</id>
+   <id alts="Japan">Asia/Tokyo</id>
   </country>
   <country code="ke" default="Africa/Nairobi" everutc="n">
-   <id>Africa/Nairobi</id>
+   <id alts="Africa/Asmera">Africa/Nairobi</id>
   </country>
   <country code="kg" default="Asia/Bishkek" everutc="n">
    <id>Asia/Bishkek</id>
@@ -455,7 +455,7 @@
    <id>Asia/Pyongyang</id>
   </country>
   <country code="kr" default="Asia/Seoul" everutc="n">
-   <id>Asia/Seoul</id>
+   <id alts="ROK">Asia/Seoul</id>
   </country>
   <country code="kw" default="Asia/Kuwait" everutc="n">
    <id>Asia/Kuwait</id>
@@ -465,12 +465,12 @@
   </country>
   <country code="kz" default="Asia/Almaty" everutc="n">
    <id>Asia/Almaty</id>
-   <id notafter="1099170000000">Asia/Qostanay</id>
+   <id notafter="1099170000000" repl="Asia/Almaty">Asia/Qostanay</id>
    <id>Asia/Oral</id>
-   <id notafter="1099173600000">Asia/Aqtau</id>
-   <id notafter="1545328800000">Asia/Qyzylorda</id>
-   <id notafter="1545328800000">Asia/Aqtobe</id>
-   <id notafter="922572000000">Asia/Atyrau</id>
+   <id notafter="1099173600000" repl="Asia/Oral">Asia/Aqtau</id>
+   <id notafter="1545328800000" repl="Asia/Oral">Asia/Qyzylorda</id>
+   <id notafter="1545328800000" repl="Asia/Oral">Asia/Aqtobe</id>
+   <id notafter="922572000000" repl="Asia/Oral">Asia/Atyrau</id>
   </country>
   <country code="la" default="Asia/Vientiane" everutc="n">
    <id>Asia/Vientiane</id>
@@ -503,7 +503,7 @@
    <id>Europe/Riga</id>
   </country>
   <country code="ly" default="Africa/Tripoli" everutc="n">
-   <id>Africa/Tripoli</id>
+   <id alts="Libya">Africa/Tripoli</id>
   </country>
   <country code="ma" default="Africa/Casablanca" everutc="y">
    <id>Africa/Casablanca</id>
@@ -512,7 +512,7 @@
    <id>Europe/Monaco</id>
   </country>
   <country code="md" default="Europe/Chisinau" everutc="n">
-   <id>Europe/Chisinau</id>
+   <id alts="Europe/Tiraspol">Europe/Chisinau</id>
   </country>
   <country code="me" default="Europe/Podgorica" everutc="n">
    <id>Europe/Podgorica</id>
@@ -525,7 +525,7 @@
   </country>
   <country code="mh" default="Pacific/Majuro" everutc="n">
    <id>Pacific/Majuro</id>
-   <id notafter="745934400000">Pacific/Kwajalein</id>
+   <id notafter="745934400000" repl="Pacific/Majuro" alts="Kwajalein">Pacific/Kwajalein</id>
   </country>
   <country code="mk" default="Europe/Skopje" everutc="n">
    <id>Europe/Skopje</id>
@@ -534,15 +534,15 @@
    <id>Africa/Bamako</id>
   </country>
   <country code="mm" default="Asia/Yangon" everutc="n">
-   <id>Asia/Yangon</id>
+   <id alts="Asia/Rangoon">Asia/Yangon</id>
   </country>
   <country code="mn" default="Asia/Ulaanbaatar" everutc="n">
    <id>Asia/Choibalsan</id>
-   <id>Asia/Ulaanbaatar</id>
+   <id alts="Asia/Ulan_Bator">Asia/Ulaanbaatar</id>
    <id>Asia/Hovd</id>
   </country>
   <country code="mo" default="Asia/Macau" everutc="n">
-   <id>Asia/Macau</id>
+   <id alts="Asia/Macao">Asia/Macau</id>
   </country>
   <country code="mp" default="Pacific/Saipan" everutc="n">
    <id>Pacific/Saipan</id>
@@ -569,21 +569,21 @@
    <id>Africa/Blantyre</id>
   </country>
   <country code="mx" default="America/Mexico_City" everutc="n">
-   <id>America/Mexico_City</id>
-   <id notafter="407653200000">America/Merida</id>
-   <id notafter="594198000000">America/Monterrey</id>
-   <id notafter="1270371600000">America/Bahia_Banderas</id>
+   <id alts="Mexico/General">America/Mexico_City</id>
+   <id notafter="407653200000" repl="America/Mexico_City">America/Merida</id>
+   <id notafter="594198000000" repl="America/Mexico_City">America/Monterrey</id>
+   <id notafter="1270371600000" repl="America/Mexico_City">America/Bahia_Banderas</id>
    <id>America/Matamoros</id>
    <id>America/Cancun</id>
    <id>America/Chihuahua</id>
-   <id notafter="891766800000">America/Mazatlan</id>
+   <id notafter="891766800000" repl="America/Chihuahua" alts="Mexico/BajaSur">America/Mazatlan</id>
    <id>America/Hermosillo</id>
    <id>America/Ojinaga</id>
-   <id>America/Tijuana</id>
+   <id alts="America/Ensenada,America/Santa_Isabel,Mexico/BajaNorte">America/Tijuana</id>
   </country>
   <country code="my" default="Asia/Kuala_Lumpur" everutc="n">
    <id>Asia/Kuala_Lumpur</id>
-   <id notafter="378664200000">Asia/Kuching</id>
+   <id notafter="378664200000" repl="Asia/Kuala_Lumpur">Asia/Kuching</id>
   </country>
   <country code="mz" default="Africa/Maputo" everutc="n">
    <id>Africa/Maputo</id>
@@ -610,10 +610,10 @@
    <id>Europe/Amsterdam</id>
   </country>
   <country code="no" default="Europe/Oslo" everutc="n">
-   <id>Europe/Oslo</id>
+   <id alts="Atlantic/Jan_Mayen">Europe/Oslo</id>
   </country>
   <country code="np" default="Asia/Kathmandu" everutc="n">
-   <id>Asia/Kathmandu</id>
+   <id alts="Asia/Katmandu">Asia/Kathmandu</id>
   </country>
   <country code="nr" default="Pacific/Nauru" everutc="n">
    <id>Pacific/Nauru</id>
@@ -622,8 +622,8 @@
    <id>Pacific/Niue</id>
   </country>
   <country code="nz" default="Pacific/Auckland" defaultBoost="y" everutc="n">
-   <id>Pacific/Auckland</id>
-   <id>Pacific/Chatham</id>
+   <id alts="Antarctica/South_Pole,NZ">Pacific/Auckland</id>
+   <id alts="NZ-CHAT">Pacific/Chatham</id>
   </country>
   <country code="om" default="Asia/Muscat" everutc="n">
    <id>Asia/Muscat</id>
@@ -650,7 +650,7 @@
    <id>Asia/Karachi</id>
   </country>
   <country code="pl" default="Europe/Warsaw" everutc="n">
-   <id>Europe/Warsaw</id>
+   <id alts="Poland">Europe/Warsaw</id>
   </country>
   <country code="pm" default="America/Miquelon" everutc="n">
    <id>America/Miquelon</id>
@@ -663,11 +663,11 @@
   </country>
   <country code="ps" default="Asia/Gaza" everutc="n">
    <id>Asia/Hebron</id>
-   <id notafter="1317330000000">Asia/Gaza</id>
+   <id notafter="1317330000000" repl="Asia/Hebron">Asia/Gaza</id>
   </country>
   <country code="pt" default="Europe/Lisbon" everutc="y">
-   <id>Europe/Lisbon</id>
-   <id notafter="828234000000">Atlantic/Madeira</id>
+   <id alts="Portugal">Europe/Lisbon</id>
+   <id notafter="828234000000" repl="Europe/Lisbon">Atlantic/Madeira</id>
    <id>Atlantic/Azores</id>
   </country>
   <country code="pw" default="Pacific/Palau" everutc="n">
@@ -695,24 +695,24 @@
    <id>Asia/Sakhalin</id>
    <id>Asia/Srednekolymsk</id>
    <id>Asia/Vladivostok</id>
-   <id notafter="1315828800000">Asia/Ust-Nera</id>
+   <id notafter="1315828800000" repl="Asia/Vladivostok">Asia/Ust-Nera</id>
    <id>Asia/Chita</id>
-   <id notafter="1459015200000">Asia/Yakutsk</id>
-   <id notafter="1315832400000">Asia/Khandyga</id>
+   <id notafter="1459015200000" repl="Asia/Chita">Asia/Yakutsk</id>
+   <id notafter="1315832400000" repl="Asia/Chita">Asia/Khandyga</id>
    <id>Asia/Irkutsk</id>
    <id>Asia/Krasnoyarsk</id>
-   <id notafter="1459022400000">Asia/Novokuznetsk</id>
+   <id notafter="1459022400000" repl="Asia/Krasnoyarsk">Asia/Novokuznetsk</id>
    <id>Asia/Novosibirsk</id>
    <id>Asia/Barnaul</id>
-   <id notafter="1464465600000">Asia/Tomsk</id>
+   <id notafter="1464465600000" repl="Asia/Barnaul">Asia/Tomsk</id>
    <id>Asia/Omsk</id>
    <id>Asia/Yekaterinburg</id>
    <id>Europe/Samara</id>
    <id>Europe/Saratov</id>
-   <id notafter="1480806000000">Europe/Ulyanovsk</id>
-   <id notafter="701823600000">Europe/Astrakhan</id>
+   <id notafter="1480806000000" repl="Europe/Saratov">Europe/Ulyanovsk</id>
+   <id notafter="701823600000" repl="Europe/Saratov">Europe/Astrakhan</id>
    <id>Europe/Volgograd</id>
-   <id>Europe/Moscow</id>
+   <id alts="W-SU">Europe/Moscow</id>
    <id>Europe/Kirov</id>
    <id>Europe/Kaliningrad</id>
   </country>
@@ -735,7 +735,7 @@
    <id>Europe/Stockholm</id>
   </country>
   <country code="sg" default="Asia/Singapore" everutc="n">
-   <id>Asia/Singapore</id>
+   <id alts="Singapore">Asia/Singapore</id>
   </country>
   <country code="sh" default="Atlantic/St_Helena" everutc="y">
    <id>Atlantic/St_Helena</id>
@@ -807,7 +807,7 @@
    <id>Asia/Dili</id>
   </country>
   <country code="tm" default="Asia/Ashgabat" everutc="n">
-   <id>Asia/Ashgabat</id>
+   <id alts="Asia/Ashkhabad">Asia/Ashgabat</id>
   </country>
   <country code="tn" default="Africa/Tunis" everutc="n">
    <id>Africa/Tunis</id>
@@ -816,24 +816,24 @@
    <id>Pacific/Tongatapu</id>
   </country>
   <country code="tr" default="Europe/Istanbul" everutc="n">
-   <id>Europe/Istanbul</id>
+   <id alts="Turkey">Europe/Istanbul</id>
   </country>
   <country code="tt" default="America/Port_of_Spain" everutc="n">
-   <id>America/Port_of_Spain</id>
+   <id alts="America/Virgin">America/Port_of_Spain</id>
   </country>
   <country code="tv" default="Pacific/Funafuti" everutc="n">
    <id>Pacific/Funafuti</id>
   </country>
   <country code="tw" default="Asia/Taipei" everutc="n">
-   <id>Asia/Taipei</id>
+   <id alts="ROC">Asia/Taipei</id>
   </country>
   <country code="tz" default="Africa/Dar_es_Salaam" everutc="n">
    <id>Africa/Dar_es_Salaam</id>
   </country>
   <country code="ua" default="Europe/Kiev" everutc="n">
    <id>Europe/Kiev</id>
-   <id notafter="686102400000">Europe/Zaporozhye</id>
-   <id notafter="686091600000">Europe/Uzhgorod</id>
+   <id notafter="686102400000" repl="Europe/Kiev">Europe/Zaporozhye</id>
+   <id notafter="686091600000" repl="Europe/Kiev">Europe/Uzhgorod</id>
    <id picker="n">Europe/Simferopol</id>
   </country>
   <country code="ug" default="Africa/Kampala" everutc="n">
@@ -844,42 +844,42 @@
    <id>Pacific/Midway</id>
   </country>
   <country code="us" default="America/New_York" everutc="n">
-   <id>America/New_York</id>
-   <id notafter="152089200000">America/Kentucky/Louisville</id>
-   <id notafter="167814000000">America/Detroit</id>
-   <id notafter="1130652000000">America/Indiana/Indianapolis</id>
-   <id notafter="1194159600000">America/Indiana/Vincennes</id>
-   <id notafter="972802800000">America/Kentucky/Monticello</id>
-   <id notafter="247042800000">America/Indiana/Petersburg</id>
-   <id notafter="1173600000000">America/Indiana/Winamac</id>
-   <id notafter="89186400000">America/Indiana/Vevay</id>
-   <id notafter="183535200000">America/Indiana/Marengo</id>
-   <id>America/Chicago</id>
-   <id notafter="104918400000">America/Menominee</id>
-   <id notafter="1143964800000">America/Indiana/Tell_City</id>
-   <id notafter="688546800000">America/Indiana/Knox</id>
-   <id notafter="1289116800000">America/North_Dakota/Beulah</id>
-   <id notafter="1067155200000">America/North_Dakota/New_Salem</id>
-   <id notafter="720000000000">America/North_Dakota/Center</id>
-   <id>America/Denver</id>
-   <id>America/Phoenix</id>
-   <id notafter="129114000000">America/Boise</id>
-   <id>America/Los_Angeles</id>
-   <id>America/Anchorage</id>
-   <id notafter="436359600000">America/Juneau</id>
-   <id notafter="341402400000">America/Sitka</id>
-   <id notafter="436363200000">America/Nome</id>
-   <id notafter="1547978400000">America/Metlakatla</id>
-   <id notafter="436356000000">America/Yakutat</id>
-   <id>Pacific/Honolulu</id>
-   <id>America/Adak</id>
+   <id alts="US/Eastern">America/New_York</id>
+   <id notafter="152089200000" repl="America/New_York" alts="America/Louisville">America/Kentucky/Louisville</id>
+   <id notafter="167814000000" repl="America/New_York" alts="US/Michigan">America/Detroit</id>
+   <id notafter="1130652000000" repl="America/New_York" alts="America/Fort_Wayne,America/Indianapolis,US/East-Indiana">America/Indiana/Indianapolis</id>
+   <id notafter="1194159600000" repl="America/New_York">America/Indiana/Vincennes</id>
+   <id notafter="972802800000" repl="America/New_York">America/Kentucky/Monticello</id>
+   <id notafter="247042800000" repl="America/New_York">America/Indiana/Petersburg</id>
+   <id notafter="1173600000000" repl="America/New_York">America/Indiana/Winamac</id>
+   <id notafter="89186400000" repl="America/New_York">America/Indiana/Vevay</id>
+   <id notafter="183535200000" repl="America/New_York">America/Indiana/Marengo</id>
+   <id alts="US/Central">America/Chicago</id>
+   <id notafter="104918400000" repl="America/Chicago">America/Menominee</id>
+   <id notafter="1143964800000" repl="America/Chicago">America/Indiana/Tell_City</id>
+   <id notafter="688546800000" repl="America/Chicago" alts="America/Knox_IN,US/Indiana-Starke">America/Indiana/Knox</id>
+   <id notafter="1289116800000" repl="America/Chicago">America/North_Dakota/Beulah</id>
+   <id notafter="1067155200000" repl="America/Chicago">America/North_Dakota/New_Salem</id>
+   <id notafter="720000000000" repl="America/Chicago">America/North_Dakota/Center</id>
+   <id alts="America/Shiprock,Navajo,US/Mountain">America/Denver</id>
+   <id alts="US/Arizona">America/Phoenix</id>
+   <id notafter="129114000000" repl="America/Phoenix">America/Boise</id>
+   <id alts="US/Pacific">America/Los_Angeles</id>
+   <id alts="US/Alaska">America/Anchorage</id>
+   <id notafter="436359600000" repl="America/Anchorage">America/Juneau</id>
+   <id notafter="341402400000" repl="America/Anchorage">America/Sitka</id>
+   <id notafter="436363200000" repl="America/Anchorage">America/Nome</id>
+   <id notafter="1547978400000" repl="America/Anchorage">America/Metlakatla</id>
+   <id notafter="436356000000" repl="America/Anchorage">America/Yakutat</id>
+   <id alts="Pacific/Johnston,US/Hawaii">Pacific/Honolulu</id>
+   <id alts="America/Atka,US/Aleutian">America/Adak</id>
   </country>
   <country code="uy" default="America/Montevideo" everutc="n">
    <id>America/Montevideo</id>
   </country>
   <country code="uz" default="Asia/Tashkent" everutc="n">
    <id>Asia/Tashkent</id>
-   <id notafter="670366800000">Asia/Samarkand</id>
+   <id notafter="670366800000" repl="Asia/Tashkent">Asia/Samarkand</id>
   </country>
   <country code="va" default="Europe/Vatican" everutc="n">
    <id>Europe/Vatican</id>
@@ -897,7 +897,7 @@
    <id>America/St_Thomas</id>
   </country>
   <country code="vn" default="Asia/Ho_Chi_Minh" everutc="n">
-   <id>Asia/Ho_Chi_Minh</id>
+   <id alts="Asia/Saigon">Asia/Ho_Chi_Minh</id>
   </country>
   <country code="vu" default="Pacific/Efate" everutc="n">
    <id>Pacific/Efate</id>
diff --git a/testing/data/test1/output_data/distro/distro.zip b/testing/data/test1/output_data/distro/distro.zip
index 333d9d1..2e5603d 100644
--- a/testing/data/test1/output_data/distro/distro.zip
+++ b/testing/data/test1/output_data/distro/distro.zip
Binary files differ
diff --git a/testing/data/test1/output_data/iana/tzdata b/testing/data/test1/output_data/iana/tzdata
index c5a28a4..e60fb5e 100644
--- a/testing/data/test1/output_data/iana/tzdata
+++ b/testing/data/test1/output_data/iana/tzdata
Binary files differ
diff --git a/testing/data/test1/output_data/version/tz_version b/testing/data/test1/output_data/version/tz_version
index e1e8f45..b843d8a 100644
--- a/testing/data/test1/output_data/version/tz_version
+++ b/testing/data/test1/output_data/version/tz_version
@@ -1 +1 @@
-004.001|2030a|001
\ No newline at end of file
+005.001|2030a|001
\ No newline at end of file
diff --git a/testing/data/test2/output_data/android/tzlookup.xml b/testing/data/test2/output_data/android/tzlookup.xml
index ef5f3dc..681f304 100644
--- a/testing/data/test2/output_data/android/tzlookup.xml
+++ b/testing/data/test2/output_data/android/tzlookup.xml
@@ -41,38 +41,38 @@
    <id>Antarctica/Palmer</id>
   </country>
   <country code="ar" default="America/Argentina/Buenos_Aires" defaultBoost="y" everutc="n">
-   <id>America/Argentina/Buenos_Aires</id>
-   <id notafter="687931200000">America/Argentina/Cordoba</id>
-   <id notafter="1237082400000">America/Argentina/Mendoza</id>
-   <id notafter="1087099200000">America/Argentina/Tucuman</id>
-   <id notafter="1096171200000">America/Argentina/Salta</id>
-   <id notafter="1090728000000">America/Argentina/San_Juan</id>
-   <id notafter="687931200000">America/Argentina/Jujuy</id>
-   <id notafter="1087704000000">America/Argentina/Catamarca</id>
-   <id notafter="687931200000">America/Argentina/La_Rioja</id>
-   <id notafter="673588800000">America/Argentina/Rio_Gallegos</id>
-   <id notafter="1087704000000">America/Argentina/Ushuaia</id>
+   <id alts="America/Buenos_Aires">America/Argentina/Buenos_Aires</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires" alts="America/Cordoba,America/Rosario">America/Argentina/Cordoba</id>
+   <id notafter="1237082400000" repl="America/Argentina/Buenos_Aires" alts="America/Mendoza">America/Argentina/Mendoza</id>
+   <id notafter="1087099200000" repl="America/Argentina/Buenos_Aires">America/Argentina/Tucuman</id>
+   <id notafter="1096171200000" repl="America/Argentina/Buenos_Aires">America/Argentina/Salta</id>
+   <id notafter="1090728000000" repl="America/Argentina/Buenos_Aires">America/Argentina/San_Juan</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires" alts="America/Jujuy">America/Argentina/Jujuy</id>
+   <id notafter="1087704000000" repl="America/Argentina/Buenos_Aires" alts="America/Argentina/ComodRivadavia,America/Catamarca">America/Argentina/Catamarca</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires">America/Argentina/La_Rioja</id>
+   <id notafter="673588800000" repl="America/Argentina/Buenos_Aires">America/Argentina/Rio_Gallegos</id>
+   <id notafter="1087704000000" repl="America/Argentina/Buenos_Aires">America/Argentina/Ushuaia</id>
    <id>America/Argentina/San_Luis</id>
   </country>
   <country code="as" default="Pacific/Pago_Pago" everutc="n">
-   <id>Pacific/Pago_Pago</id>
+   <id alts="Pacific/Samoa,US/Samoa">Pacific/Pago_Pago</id>
   </country>
   <country code="at" default="Europe/Vienna" everutc="n">
    <id>Europe/Vienna</id>
   </country>
   <country code="au" default="Australia/Sydney" everutc="n">
-   <id>Australia/Sydney</id>
-   <id notafter="796147200000">Australia/Melbourne</id>
-   <id notafter="1193500800000">Australia/Hobart</id>
-   <id notafter="37728000000">Australia/Currie</id>
-   <id>Australia/Brisbane</id>
-   <id notafter="762883200000">Australia/Lindeman</id>
+   <id alts="Australia/ACT,Australia/Canberra,Australia/NSW">Australia/Sydney</id>
+   <id notafter="796147200000" repl="Australia/Sydney" alts="Australia/Victoria">Australia/Melbourne</id>
+   <id notafter="1193500800000" repl="Australia/Sydney" alts="Australia/Tasmania">Australia/Hobart</id>
+   <id notafter="37728000000" repl="Australia/Sydney">Australia/Currie</id>
+   <id alts="Australia/Queensland">Australia/Brisbane</id>
+   <id notafter="762883200000" repl="Australia/Brisbane">Australia/Lindeman</id>
    <id>Antarctica/Macquarie</id>
-   <id>Australia/Lord_Howe</id>
-   <id>Australia/Adelaide</id>
-   <id notafter="796149000000">Australia/Broken_Hill</id>
-   <id>Australia/Darwin</id>
-   <id>Australia/Perth</id>
+   <id alts="Australia/LHI">Australia/Lord_Howe</id>
+   <id alts="Australia/South">Australia/Adelaide</id>
+   <id notafter="796149000000" repl="Australia/Adelaide" alts="Australia/Yancowinna">Australia/Broken_Hill</id>
+   <id alts="Australia/North">Australia/Darwin</id>
+   <id alts="Australia/West">Australia/Perth</id>
    <id>Australia/Eucla</id>
   </country>
   <country code="aw" default="America/Aruba" everutc="n">
@@ -91,7 +91,7 @@
    <id>America/Barbados</id>
   </country>
   <country code="bd" default="Asia/Dhaka" everutc="n">
-   <id>Asia/Dhaka</id>
+   <id alts="Asia/Dacca">Asia/Dhaka</id>
   </country>
   <country code="be" default="Europe/Brussels" everutc="n">
    <id>Europe/Brussels</id>
@@ -127,28 +127,28 @@
    <id>America/Kralendijk</id>
   </country>
   <country code="br" default="America/Noronha" everutc="n">
-   <id>America/Noronha</id>
-   <id>America/Sao_Paulo</id>
-   <id notafter="1550368800000">America/Bahia</id>
-   <id notafter="1214280000000">America/Santarem</id>
-   <id notafter="1330221600000">America/Recife</id>
-   <id notafter="972180000000">America/Fortaleza</id>
-   <id notafter="1013911200000">America/Belem</id>
-   <id notafter="824004000000">America/Maceio</id>
-   <id notafter="1361066400000">America/Araguaina</id>
-   <id>America/Manaus</id>
-   <id notafter="1550372400000">America/Cuiaba</id>
-   <id notafter="1076814000000">America/Campo_Grande</id>
-   <id notafter="761713200000">America/Porto_Velho</id>
-   <id notafter="971578800000">America/Boa_Vista</id>
-   <id>America/Rio_Branco</id>
-   <id notafter="761716800000">America/Eirunepe</id>
+   <id alts="Brazil/DeNoronha">America/Noronha</id>
+   <id alts="Brazil/East">America/Sao_Paulo</id>
+   <id notafter="1550368800000" repl="America/Sao_Paulo">America/Bahia</id>
+   <id notafter="1214280000000" repl="America/Sao_Paulo">America/Santarem</id>
+   <id notafter="1330221600000" repl="America/Sao_Paulo">America/Recife</id>
+   <id notafter="972180000000" repl="America/Sao_Paulo">America/Fortaleza</id>
+   <id notafter="1013911200000" repl="America/Sao_Paulo">America/Belem</id>
+   <id notafter="824004000000" repl="America/Sao_Paulo">America/Maceio</id>
+   <id notafter="1361066400000" repl="America/Sao_Paulo">America/Araguaina</id>
+   <id alts="Brazil/West">America/Manaus</id>
+   <id notafter="1550372400000" repl="America/Manaus">America/Cuiaba</id>
+   <id notafter="1076814000000" repl="America/Manaus">America/Campo_Grande</id>
+   <id notafter="761713200000" repl="America/Manaus">America/Porto_Velho</id>
+   <id notafter="971578800000" repl="America/Manaus">America/Boa_Vista</id>
+   <id alts="America/Porto_Acre,Brazil/Acre">America/Rio_Branco</id>
+   <id notafter="761716800000" repl="America/Rio_Branco">America/Eirunepe</id>
   </country>
   <country code="bs" default="America/Nassau" everutc="n">
    <id>America/Nassau</id>
   </country>
   <country code="bt" default="Asia/Thimphu" everutc="n">
-   <id>Asia/Thimphu</id>
+   <id alts="Asia/Thimbu">Asia/Thimphu</id>
   </country>
   <country code="bw" default="Africa/Gaborone" everutc="n">
    <id>Africa/Gaborone</id>
@@ -160,34 +160,34 @@
    <id>America/Belize</id>
   </country>
   <country code="ca" default="America/Toronto" everutc="n">
-   <id>America/Toronto</id>
-   <id>America/Vancouver</id>
-   <id>America/Edmonton</id>
-   <id>America/Winnipeg</id>
-   <id>America/Halifax</id>
-   <id>America/St_Johns</id>
-   <id notafter="1162098000000">America/Moncton</id>
-   <id notafter="57733200000">America/Glace_Bay</id>
-   <id notafter="1299996000000">America/Goose_Bay</id>
+   <id alts="America/Montreal,Canada/Eastern">America/Toronto</id>
+   <id alts="Canada/Pacific">America/Vancouver</id>
+   <id alts="Canada/Mountain">America/Edmonton</id>
+   <id alts="Canada/Central">America/Winnipeg</id>
+   <id alts="Canada/Atlantic">America/Halifax</id>
+   <id alts="Canada/Newfoundland">America/St_Johns</id>
+   <id notafter="1162098000000" repl="America/Halifax">America/Moncton</id>
+   <id notafter="57733200000" repl="America/Halifax">America/Glace_Bay</id>
+   <id notafter="1299996000000" repl="America/Halifax">America/Goose_Bay</id>
    <id>America/Blanc-Sablon</id>
-   <id notafter="120636000000">America/Thunder_Bay</id>
-   <id notafter="972802800000">America/Iqaluit</id>
-   <id notafter="89186400000">America/Nipigon</id>
-   <id notafter="796806000000">America/Pangnirtung</id>
-   <id>America/Atikokan</id>
-   <id>America/Regina</id>
-   <id notafter="73472400000">America/Swift_Current</id>
-   <id notafter="1130659200000">America/Rankin_Inlet</id>
-   <id notafter="986112000000">America/Rainy_River</id>
-   <id notafter="1173600000000">America/Resolute</id>
-   <id notafter="309945600000">America/Yellowknife</id>
-   <id notafter="1583661600000">America/Dawson_Creek</id>
-   <id notafter="84013200000">America/Creston</id>
-   <id notafter="1425808800000">America/Fort_Nelson</id>
-   <id notafter="294228000000">America/Inuvik</id>
-   <id notafter="986115600000">America/Cambridge_Bay</id>
-   <id notafter="120646800000">America/Dawson</id>
-   <id>America/Whitehorse</id>
+   <id notafter="120636000000" repl="America/Toronto">America/Thunder_Bay</id>
+   <id notafter="972802800000" repl="America/Toronto">America/Iqaluit</id>
+   <id notafter="89186400000" repl="America/Toronto">America/Nipigon</id>
+   <id notafter="796806000000" repl="America/Toronto">America/Pangnirtung</id>
+   <id alts="America/Coral_Harbour">America/Atikokan</id>
+   <id alts="Canada/Saskatchewan">America/Regina</id>
+   <id notafter="73472400000" repl="America/Winnipeg">America/Swift_Current</id>
+   <id notafter="1130659200000" repl="America/Winnipeg">America/Rankin_Inlet</id>
+   <id notafter="986112000000" repl="America/Winnipeg">America/Rainy_River</id>
+   <id notafter="1173600000000" repl="America/Winnipeg">America/Resolute</id>
+   <id notafter="309945600000" repl="America/Edmonton">America/Yellowknife</id>
+   <id notafter="1583661600000" repl="America/Edmonton">America/Dawson_Creek</id>
+   <id notafter="84013200000" repl="America/Edmonton">America/Creston</id>
+   <id notafter="1425808800000" repl="America/Edmonton">America/Fort_Nelson</id>
+   <id notafter="294228000000" repl="America/Edmonton">America/Inuvik</id>
+   <id notafter="986115600000" repl="America/Edmonton">America/Cambridge_Bay</id>
+   <id notafter="120646800000" repl="America/Edmonton">America/Dawson</id>
+   <id alts="Canada/Yukon">America/Whitehorse</id>
   </country>
   <country code="cc" default="Indian/Cocos" everutc="n">
    <id>Indian/Cocos</id>
@@ -206,22 +206,22 @@
    <id>Europe/Zurich</id>
   </country>
   <country code="ci" default="Africa/Abidjan" everutc="y">
-   <id>Africa/Abidjan</id>
+   <id alts="Africa/Timbuktu">Africa/Abidjan</id>
   </country>
   <country code="ck" default="Pacific/Rarotonga" everutc="n">
    <id>Pacific/Rarotonga</id>
   </country>
   <country code="cl" default="America/Santiago" everutc="n">
    <id>America/Punta_Arenas</id>
-   <id>America/Santiago</id>
-   <id>Pacific/Easter</id>
+   <id alts="Chile/Continental">America/Santiago</id>
+   <id alts="Chile/EasterIsland">Pacific/Easter</id>
   </country>
   <country code="cm" default="Africa/Douala" everutc="n">
    <id>Africa/Douala</id>
   </country>
   <country code="cn" default="Asia/Shanghai" defaultBoost="y" everutc="n">
-   <id>Asia/Shanghai</id>
-   <id>Asia/Urumqi</id>
+   <id alts="Asia/Chongqing,Asia/Chungking,Asia/Harbin,PRC">Asia/Shanghai</id>
+   <id alts="Asia/Kashgar">Asia/Urumqi</id>
   </country>
   <country code="co" default="America/Bogota" everutc="n">
    <id>America/Bogota</id>
@@ -230,7 +230,7 @@
    <id>America/Costa_Rica</id>
   </country>
   <country code="cu" default="America/Havana" everutc="n">
-   <id>America/Havana</id>
+   <id alts="Cuba">America/Havana</id>
   </country>
   <country code="cv" default="Atlantic/Cape_Verde" everutc="n">
    <id>Atlantic/Cape_Verde</id>
@@ -250,7 +250,7 @@
   </country>
   <country code="de" default="Europe/Berlin" everutc="n">
    <id>Europe/Berlin</id>
-   <id notafter="338950800000">Europe/Busingen</id>
+   <id notafter="338950800000" repl="Europe/Berlin">Europe/Busingen</id>
   </country>
   <country code="dj" default="Africa/Djibouti" everutc="n">
    <id>Africa/Djibouti</id>
@@ -275,7 +275,7 @@
    <id>Europe/Tallinn</id>
   </country>
   <country code="eg" default="Africa/Cairo" everutc="n">
-   <id>Africa/Cairo</id>
+   <id alts="Egypt">Africa/Cairo</id>
   </country>
   <country code="eh" default="Africa/El_Aaiun" everutc="y">
    <id>Africa/El_Aaiun</id>
@@ -285,7 +285,7 @@
   </country>
   <country code="es" default="Europe/Madrid" everutc="y">
    <id>Europe/Madrid</id>
-   <id notafter="496803600000">Africa/Ceuta</id>
+   <id notafter="496803600000" repl="Europe/Madrid">Africa/Ceuta</id>
    <id>Atlantic/Canary</id>
   </country>
   <country code="et" default="Africa/Addis_Ababa" everutc="n">
@@ -301,12 +301,12 @@
    <id>Atlantic/Stanley</id>
   </country>
   <country code="fm" default="Pacific/Pohnpei" everutc="n">
-   <id>Pacific/Pohnpei</id>
+   <id alts="Pacific/Ponape">Pacific/Pohnpei</id>
    <id>Pacific/Kosrae</id>
-   <id>Pacific/Chuuk</id>
+   <id alts="Pacific/Truk,Pacific/Yap">Pacific/Chuuk</id>
   </country>
   <country code="fo" default="Atlantic/Faroe" everutc="y">
-   <id>Atlantic/Faroe</id>
+   <id alts="Atlantic/Faeroe">Atlantic/Faroe</id>
   </country>
   <country code="fr" default="Europe/Paris" everutc="n">
    <id>Europe/Paris</id>
@@ -315,7 +315,7 @@
    <id>Africa/Libreville</id>
   </country>
   <country code="gb" default="Europe/London" everutc="y">
-   <id>Europe/London</id>
+   <id alts="Europe/Belfast,GB,GB-Eire">Europe/London</id>
   </country>
   <country code="gd" default="America/Grenada" everutc="n">
    <id>America/Grenada</id>
@@ -338,7 +338,7 @@
   <country code="gl" default="America/Nuuk" everutc="y">
    <id>America/Danmarkshavn</id>
    <id>America/Scoresbysund</id>
-   <id>America/Nuuk</id>
+   <id alts="America/Godthab">America/Nuuk</id>
    <id>America/Thule</id>
   </country>
   <country code="gm" default="Africa/Banjul" everutc="y">
@@ -372,7 +372,7 @@
    <id>America/Guyana</id>
   </country>
   <country code="hk" default="Asia/Hong_Kong" everutc="n">
-   <id>Asia/Hong_Kong</id>
+   <id alts="Hongkong">Asia/Hong_Kong</id>
   </country>
   <country code="hn" default="America/Tegucigalpa" everutc="n">
    <id>America/Tegucigalpa</id>
@@ -388,21 +388,21 @@
   </country>
   <country code="id" default="Asia/Jakarta" everutc="n">
    <id>Asia/Jayapura</id>
-   <id>Asia/Makassar</id>
+   <id alts="Asia/Ujung_Pandang">Asia/Makassar</id>
    <id>Asia/Jakarta</id>
-   <id notafter="567964800000">Asia/Pontianak</id>
+   <id notafter="567964800000" repl="Asia/Jakarta">Asia/Pontianak</id>
   </country>
   <country code="ie" default="Europe/Dublin" everutc="y">
-   <id>Europe/Dublin</id>
+   <id alts="Eire">Europe/Dublin</id>
   </country>
   <country code="il" default="Asia/Jerusalem" everutc="n">
-   <id>Asia/Jerusalem</id>
+   <id alts="Asia/Tel_Aviv,Israel">Asia/Jerusalem</id>
   </country>
   <country code="im" default="Europe/Isle_of_Man" everutc="y">
    <id>Europe/Isle_of_Man</id>
   </country>
   <country code="in" default="Asia/Kolkata" everutc="n">
-   <id>Asia/Kolkata</id>
+   <id alts="Asia/Calcutta">Asia/Kolkata</id>
   </country>
   <country code="io" default="Indian/Chagos" everutc="n">
    <id>Indian/Chagos</id>
@@ -411,10 +411,10 @@
    <id>Asia/Baghdad</id>
   </country>
   <country code="ir" default="Asia/Tehran" everutc="n">
-   <id>Asia/Tehran</id>
+   <id alts="Iran">Asia/Tehran</id>
   </country>
   <country code="is" default="Atlantic/Reykjavik" everutc="y">
-   <id>Atlantic/Reykjavik</id>
+   <id alts="Iceland">Atlantic/Reykjavik</id>
   </country>
   <country code="it" default="Europe/Rome" everutc="n">
    <id>Europe/Rome</id>
@@ -423,16 +423,16 @@
    <id>Europe/Jersey</id>
   </country>
   <country code="jm" default="America/Jamaica" everutc="n">
-   <id>America/Jamaica</id>
+   <id alts="Jamaica">America/Jamaica</id>
   </country>
   <country code="jo" default="Asia/Amman" everutc="n">
    <id>Asia/Amman</id>
   </country>
   <country code="jp" default="Asia/Tokyo" everutc="n">
-   <id>Asia/Tokyo</id>
+   <id alts="Japan">Asia/Tokyo</id>
   </country>
   <country code="ke" default="Africa/Nairobi" everutc="n">
-   <id>Africa/Nairobi</id>
+   <id alts="Africa/Asmera">Africa/Nairobi</id>
   </country>
   <country code="kg" default="Asia/Bishkek" everutc="n">
    <id>Asia/Bishkek</id>
@@ -455,7 +455,7 @@
    <id>Asia/Pyongyang</id>
   </country>
   <country code="kr" default="Asia/Seoul" everutc="n">
-   <id>Asia/Seoul</id>
+   <id alts="ROK">Asia/Seoul</id>
   </country>
   <country code="kw" default="Asia/Kuwait" everutc="n">
    <id>Asia/Kuwait</id>
@@ -465,12 +465,12 @@
   </country>
   <country code="kz" default="Asia/Almaty" everutc="n">
    <id>Asia/Almaty</id>
-   <id notafter="1099170000000">Asia/Qostanay</id>
+   <id notafter="1099170000000" repl="Asia/Almaty">Asia/Qostanay</id>
    <id>Asia/Oral</id>
-   <id notafter="1099173600000">Asia/Aqtau</id>
-   <id notafter="1545328800000">Asia/Qyzylorda</id>
-   <id notafter="1545328800000">Asia/Aqtobe</id>
-   <id notafter="922572000000">Asia/Atyrau</id>
+   <id notafter="1099173600000" repl="Asia/Oral">Asia/Aqtau</id>
+   <id notafter="1545328800000" repl="Asia/Oral">Asia/Qyzylorda</id>
+   <id notafter="1545328800000" repl="Asia/Oral">Asia/Aqtobe</id>
+   <id notafter="922572000000" repl="Asia/Oral">Asia/Atyrau</id>
   </country>
   <country code="la" default="Asia/Vientiane" everutc="n">
    <id>Asia/Vientiane</id>
@@ -503,7 +503,7 @@
    <id>Europe/Riga</id>
   </country>
   <country code="ly" default="Africa/Tripoli" everutc="n">
-   <id>Africa/Tripoli</id>
+   <id alts="Libya">Africa/Tripoli</id>
   </country>
   <country code="ma" default="Africa/Casablanca" everutc="y">
    <id>Africa/Casablanca</id>
@@ -512,7 +512,7 @@
    <id>Europe/Monaco</id>
   </country>
   <country code="md" default="Europe/Chisinau" everutc="n">
-   <id>Europe/Chisinau</id>
+   <id alts="Europe/Tiraspol">Europe/Chisinau</id>
   </country>
   <country code="me" default="Europe/Podgorica" everutc="n">
    <id>Europe/Podgorica</id>
@@ -525,7 +525,7 @@
   </country>
   <country code="mh" default="Pacific/Majuro" everutc="n">
    <id>Pacific/Majuro</id>
-   <id notafter="745934400000">Pacific/Kwajalein</id>
+   <id notafter="745934400000" repl="Pacific/Majuro" alts="Kwajalein">Pacific/Kwajalein</id>
   </country>
   <country code="mk" default="Europe/Skopje" everutc="n">
    <id>Europe/Skopje</id>
@@ -534,15 +534,15 @@
    <id>Africa/Bamako</id>
   </country>
   <country code="mm" default="Asia/Yangon" everutc="n">
-   <id>Asia/Yangon</id>
+   <id alts="Asia/Rangoon">Asia/Yangon</id>
   </country>
   <country code="mn" default="Asia/Ulaanbaatar" everutc="n">
    <id>Asia/Choibalsan</id>
-   <id>Asia/Ulaanbaatar</id>
+   <id alts="Asia/Ulan_Bator">Asia/Ulaanbaatar</id>
    <id>Asia/Hovd</id>
   </country>
   <country code="mo" default="Asia/Macau" everutc="n">
-   <id>Asia/Macau</id>
+   <id alts="Asia/Macao">Asia/Macau</id>
   </country>
   <country code="mp" default="Pacific/Saipan" everutc="n">
    <id>Pacific/Saipan</id>
@@ -569,21 +569,21 @@
    <id>Africa/Blantyre</id>
   </country>
   <country code="mx" default="America/Mexico_City" everutc="n">
-   <id>America/Mexico_City</id>
-   <id notafter="407653200000">America/Merida</id>
-   <id notafter="594198000000">America/Monterrey</id>
-   <id notafter="1270371600000">America/Bahia_Banderas</id>
+   <id alts="Mexico/General">America/Mexico_City</id>
+   <id notafter="407653200000" repl="America/Mexico_City">America/Merida</id>
+   <id notafter="594198000000" repl="America/Mexico_City">America/Monterrey</id>
+   <id notafter="1270371600000" repl="America/Mexico_City">America/Bahia_Banderas</id>
    <id>America/Matamoros</id>
    <id>America/Cancun</id>
    <id>America/Chihuahua</id>
-   <id notafter="891766800000">America/Mazatlan</id>
+   <id notafter="891766800000" repl="America/Chihuahua" alts="Mexico/BajaSur">America/Mazatlan</id>
    <id>America/Hermosillo</id>
    <id>America/Ojinaga</id>
-   <id>America/Tijuana</id>
+   <id alts="America/Ensenada,America/Santa_Isabel,Mexico/BajaNorte">America/Tijuana</id>
   </country>
   <country code="my" default="Asia/Kuala_Lumpur" everutc="n">
    <id>Asia/Kuala_Lumpur</id>
-   <id notafter="378664200000">Asia/Kuching</id>
+   <id notafter="378664200000" repl="Asia/Kuala_Lumpur">Asia/Kuching</id>
   </country>
   <country code="mz" default="Africa/Maputo" everutc="n">
    <id>Africa/Maputo</id>
@@ -610,10 +610,10 @@
    <id>Europe/Amsterdam</id>
   </country>
   <country code="no" default="Europe/Oslo" everutc="n">
-   <id>Europe/Oslo</id>
+   <id alts="Atlantic/Jan_Mayen">Europe/Oslo</id>
   </country>
   <country code="np" default="Asia/Kathmandu" everutc="n">
-   <id>Asia/Kathmandu</id>
+   <id alts="Asia/Katmandu">Asia/Kathmandu</id>
   </country>
   <country code="nr" default="Pacific/Nauru" everutc="n">
    <id>Pacific/Nauru</id>
@@ -622,8 +622,8 @@
    <id>Pacific/Niue</id>
   </country>
   <country code="nz" default="Pacific/Auckland" defaultBoost="y" everutc="n">
-   <id>Pacific/Auckland</id>
-   <id>Pacific/Chatham</id>
+   <id alts="Antarctica/South_Pole,NZ">Pacific/Auckland</id>
+   <id alts="NZ-CHAT">Pacific/Chatham</id>
   </country>
   <country code="om" default="Asia/Muscat" everutc="n">
    <id>Asia/Muscat</id>
@@ -650,7 +650,7 @@
    <id>Asia/Karachi</id>
   </country>
   <country code="pl" default="Europe/Warsaw" everutc="n">
-   <id>Europe/Warsaw</id>
+   <id alts="Poland">Europe/Warsaw</id>
   </country>
   <country code="pm" default="America/Miquelon" everutc="n">
    <id>America/Miquelon</id>
@@ -663,11 +663,11 @@
   </country>
   <country code="ps" default="Asia/Gaza" everutc="n">
    <id>Asia/Hebron</id>
-   <id notafter="1317330000000">Asia/Gaza</id>
+   <id notafter="1317330000000" repl="Asia/Hebron">Asia/Gaza</id>
   </country>
   <country code="pt" default="Europe/Lisbon" everutc="y">
-   <id>Europe/Lisbon</id>
-   <id notafter="828234000000">Atlantic/Madeira</id>
+   <id alts="Portugal">Europe/Lisbon</id>
+   <id notafter="828234000000" repl="Europe/Lisbon">Atlantic/Madeira</id>
    <id>Atlantic/Azores</id>
   </country>
   <country code="pw" default="Pacific/Palau" everutc="n">
@@ -695,24 +695,24 @@
    <id>Asia/Sakhalin</id>
    <id>Asia/Srednekolymsk</id>
    <id>Asia/Vladivostok</id>
-   <id notafter="1315828800000">Asia/Ust-Nera</id>
+   <id notafter="1315828800000" repl="Asia/Vladivostok">Asia/Ust-Nera</id>
    <id>Asia/Chita</id>
-   <id notafter="1459015200000">Asia/Yakutsk</id>
-   <id notafter="1315832400000">Asia/Khandyga</id>
+   <id notafter="1459015200000" repl="Asia/Chita">Asia/Yakutsk</id>
+   <id notafter="1315832400000" repl="Asia/Chita">Asia/Khandyga</id>
    <id>Asia/Irkutsk</id>
    <id>Asia/Krasnoyarsk</id>
-   <id notafter="1459022400000">Asia/Novokuznetsk</id>
+   <id notafter="1459022400000" repl="Asia/Krasnoyarsk">Asia/Novokuznetsk</id>
    <id>Asia/Novosibirsk</id>
    <id>Asia/Barnaul</id>
-   <id notafter="1464465600000">Asia/Tomsk</id>
+   <id notafter="1464465600000" repl="Asia/Barnaul">Asia/Tomsk</id>
    <id>Asia/Omsk</id>
    <id>Asia/Yekaterinburg</id>
    <id>Europe/Samara</id>
    <id>Europe/Saratov</id>
-   <id notafter="1480806000000">Europe/Ulyanovsk</id>
-   <id notafter="701823600000">Europe/Astrakhan</id>
+   <id notafter="1480806000000" repl="Europe/Saratov">Europe/Ulyanovsk</id>
+   <id notafter="701823600000" repl="Europe/Saratov">Europe/Astrakhan</id>
    <id>Europe/Volgograd</id>
-   <id>Europe/Moscow</id>
+   <id alts="W-SU">Europe/Moscow</id>
    <id>Europe/Kirov</id>
    <id>Europe/Kaliningrad</id>
   </country>
@@ -735,7 +735,7 @@
    <id>Europe/Stockholm</id>
   </country>
   <country code="sg" default="Asia/Singapore" everutc="n">
-   <id>Asia/Singapore</id>
+   <id alts="Singapore">Asia/Singapore</id>
   </country>
   <country code="sh" default="Atlantic/St_Helena" everutc="y">
    <id>Atlantic/St_Helena</id>
@@ -807,7 +807,7 @@
    <id>Asia/Dili</id>
   </country>
   <country code="tm" default="Asia/Ashgabat" everutc="n">
-   <id>Asia/Ashgabat</id>
+   <id alts="Asia/Ashkhabad">Asia/Ashgabat</id>
   </country>
   <country code="tn" default="Africa/Tunis" everutc="n">
    <id>Africa/Tunis</id>
@@ -816,24 +816,24 @@
    <id>Pacific/Tongatapu</id>
   </country>
   <country code="tr" default="Europe/Istanbul" everutc="n">
-   <id>Europe/Istanbul</id>
+   <id alts="Turkey">Europe/Istanbul</id>
   </country>
   <country code="tt" default="America/Port_of_Spain" everutc="n">
-   <id>America/Port_of_Spain</id>
+   <id alts="America/Virgin">America/Port_of_Spain</id>
   </country>
   <country code="tv" default="Pacific/Funafuti" everutc="n">
    <id>Pacific/Funafuti</id>
   </country>
   <country code="tw" default="Asia/Taipei" everutc="n">
-   <id>Asia/Taipei</id>
+   <id alts="ROC">Asia/Taipei</id>
   </country>
   <country code="tz" default="Africa/Dar_es_Salaam" everutc="n">
    <id>Africa/Dar_es_Salaam</id>
   </country>
   <country code="ua" default="Europe/Kiev" everutc="n">
    <id>Europe/Kiev</id>
-   <id notafter="686102400000">Europe/Zaporozhye</id>
-   <id notafter="686091600000">Europe/Uzhgorod</id>
+   <id notafter="686102400000" repl="Europe/Kiev">Europe/Zaporozhye</id>
+   <id notafter="686091600000" repl="Europe/Kiev">Europe/Uzhgorod</id>
    <id picker="n">Europe/Simferopol</id>
   </country>
   <country code="ug" default="Africa/Kampala" everutc="n">
@@ -844,42 +844,42 @@
    <id>Pacific/Midway</id>
   </country>
   <country code="us" default="America/New_York" everutc="n">
-   <id>America/New_York</id>
-   <id notafter="152089200000">America/Kentucky/Louisville</id>
-   <id notafter="167814000000">America/Detroit</id>
-   <id notafter="1130652000000">America/Indiana/Indianapolis</id>
-   <id notafter="1194159600000">America/Indiana/Vincennes</id>
-   <id notafter="972802800000">America/Kentucky/Monticello</id>
-   <id notafter="247042800000">America/Indiana/Petersburg</id>
-   <id notafter="1173600000000">America/Indiana/Winamac</id>
-   <id notafter="89186400000">America/Indiana/Vevay</id>
-   <id notafter="183535200000">America/Indiana/Marengo</id>
-   <id>America/Chicago</id>
-   <id notafter="104918400000">America/Menominee</id>
-   <id notafter="1143964800000">America/Indiana/Tell_City</id>
-   <id notafter="688546800000">America/Indiana/Knox</id>
-   <id notafter="1289116800000">America/North_Dakota/Beulah</id>
-   <id notafter="1067155200000">America/North_Dakota/New_Salem</id>
-   <id notafter="720000000000">America/North_Dakota/Center</id>
-   <id>America/Denver</id>
-   <id>America/Phoenix</id>
-   <id notafter="129114000000">America/Boise</id>
-   <id>America/Los_Angeles</id>
-   <id>America/Anchorage</id>
-   <id notafter="436359600000">America/Juneau</id>
-   <id notafter="341402400000">America/Sitka</id>
-   <id notafter="436363200000">America/Nome</id>
-   <id notafter="1547978400000">America/Metlakatla</id>
-   <id notafter="436356000000">America/Yakutat</id>
-   <id>Pacific/Honolulu</id>
-   <id>America/Adak</id>
+   <id alts="US/Eastern">America/New_York</id>
+   <id notafter="152089200000" repl="America/New_York" alts="America/Louisville">America/Kentucky/Louisville</id>
+   <id notafter="167814000000" repl="America/New_York" alts="US/Michigan">America/Detroit</id>
+   <id notafter="1130652000000" repl="America/New_York" alts="America/Fort_Wayne,America/Indianapolis,US/East-Indiana">America/Indiana/Indianapolis</id>
+   <id notafter="1194159600000" repl="America/New_York">America/Indiana/Vincennes</id>
+   <id notafter="972802800000" repl="America/New_York">America/Kentucky/Monticello</id>
+   <id notafter="247042800000" repl="America/New_York">America/Indiana/Petersburg</id>
+   <id notafter="1173600000000" repl="America/New_York">America/Indiana/Winamac</id>
+   <id notafter="89186400000" repl="America/New_York">America/Indiana/Vevay</id>
+   <id notafter="183535200000" repl="America/New_York">America/Indiana/Marengo</id>
+   <id alts="US/Central">America/Chicago</id>
+   <id notafter="104918400000" repl="America/Chicago">America/Menominee</id>
+   <id notafter="1143964800000" repl="America/Chicago">America/Indiana/Tell_City</id>
+   <id notafter="688546800000" repl="America/Chicago" alts="America/Knox_IN,US/Indiana-Starke">America/Indiana/Knox</id>
+   <id notafter="1289116800000" repl="America/Chicago">America/North_Dakota/Beulah</id>
+   <id notafter="1067155200000" repl="America/Chicago">America/North_Dakota/New_Salem</id>
+   <id notafter="720000000000" repl="America/Chicago">America/North_Dakota/Center</id>
+   <id alts="America/Shiprock,Navajo,US/Mountain">America/Denver</id>
+   <id alts="US/Arizona">America/Phoenix</id>
+   <id notafter="129114000000" repl="America/Phoenix">America/Boise</id>
+   <id alts="US/Pacific">America/Los_Angeles</id>
+   <id alts="US/Alaska">America/Anchorage</id>
+   <id notafter="436359600000" repl="America/Anchorage">America/Juneau</id>
+   <id notafter="341402400000" repl="America/Anchorage">America/Sitka</id>
+   <id notafter="436363200000" repl="America/Anchorage">America/Nome</id>
+   <id notafter="1547978400000" repl="America/Anchorage">America/Metlakatla</id>
+   <id notafter="436356000000" repl="America/Anchorage">America/Yakutat</id>
+   <id alts="Pacific/Johnston,US/Hawaii">Pacific/Honolulu</id>
+   <id alts="America/Atka,US/Aleutian">America/Adak</id>
   </country>
   <country code="uy" default="America/Montevideo" everutc="n">
    <id>America/Montevideo</id>
   </country>
   <country code="uz" default="Asia/Tashkent" everutc="n">
    <id>Asia/Tashkent</id>
-   <id notafter="670366800000">Asia/Samarkand</id>
+   <id notafter="670366800000" repl="Asia/Tashkent">Asia/Samarkand</id>
   </country>
   <country code="va" default="Europe/Vatican" everutc="n">
    <id>Europe/Vatican</id>
@@ -897,7 +897,7 @@
    <id>America/St_Thomas</id>
   </country>
   <country code="vn" default="Asia/Ho_Chi_Minh" everutc="n">
-   <id>Asia/Ho_Chi_Minh</id>
+   <id alts="Asia/Saigon">Asia/Ho_Chi_Minh</id>
   </country>
   <country code="vu" default="Pacific/Efate" everutc="n">
    <id>Pacific/Efate</id>
diff --git a/testing/data/test2/output_data/distro/distro.zip b/testing/data/test2/output_data/distro/distro.zip
index 4a9da2a..3728847 100644
--- a/testing/data/test2/output_data/distro/distro.zip
+++ b/testing/data/test2/output_data/distro/distro.zip
Binary files differ
diff --git a/testing/data/test2/output_data/iana/tzdata b/testing/data/test2/output_data/iana/tzdata
index c2d09f8..e2b8fac 100644
--- a/testing/data/test2/output_data/iana/tzdata
+++ b/testing/data/test2/output_data/iana/tzdata
Binary files differ
diff --git a/testing/data/test2/output_data/version/tz_version b/testing/data/test2/output_data/version/tz_version
index cd062bc..63882f0 100644
--- a/testing/data/test2/output_data/version/tz_version
+++ b/testing/data/test2/output_data/version/tz_version
@@ -1 +1 @@
-004.001|2016a|001
\ No newline at end of file
+005.001|2016a|001
\ No newline at end of file
diff --git a/testing/data/test3/output_data/android/tzlookup.xml b/testing/data/test3/output_data/android/tzlookup.xml
index 6297544..8906877 100644
--- a/testing/data/test3/output_data/android/tzlookup.xml
+++ b/testing/data/test3/output_data/android/tzlookup.xml
@@ -41,38 +41,38 @@
    <id>Antarctica/Palmer</id>
   </country>
   <country code="ar" default="America/Argentina/Buenos_Aires" defaultBoost="y" everutc="n">
-   <id>America/Argentina/Buenos_Aires</id>
-   <id notafter="687931200000">America/Argentina/Cordoba</id>
-   <id notafter="1237082400000">America/Argentina/Mendoza</id>
-   <id notafter="1087099200000">America/Argentina/Tucuman</id>
-   <id notafter="1096171200000">America/Argentina/Salta</id>
-   <id notafter="1090728000000">America/Argentina/San_Juan</id>
-   <id notafter="687931200000">America/Argentina/Jujuy</id>
-   <id notafter="1087704000000">America/Argentina/Catamarca</id>
-   <id notafter="687931200000">America/Argentina/La_Rioja</id>
-   <id notafter="673588800000">America/Argentina/Rio_Gallegos</id>
-   <id notafter="1087704000000">America/Argentina/Ushuaia</id>
+   <id alts="America/Buenos_Aires">America/Argentina/Buenos_Aires</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires" alts="America/Cordoba,America/Rosario">America/Argentina/Cordoba</id>
+   <id notafter="1237082400000" repl="America/Argentina/Buenos_Aires" alts="America/Mendoza">America/Argentina/Mendoza</id>
+   <id notafter="1087099200000" repl="America/Argentina/Buenos_Aires">America/Argentina/Tucuman</id>
+   <id notafter="1096171200000" repl="America/Argentina/Buenos_Aires">America/Argentina/Salta</id>
+   <id notafter="1090728000000" repl="America/Argentina/Buenos_Aires">America/Argentina/San_Juan</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires" alts="America/Jujuy">America/Argentina/Jujuy</id>
+   <id notafter="1087704000000" repl="America/Argentina/Buenos_Aires" alts="America/Argentina/ComodRivadavia,America/Catamarca">America/Argentina/Catamarca</id>
+   <id notafter="687931200000" repl="America/Argentina/Buenos_Aires">America/Argentina/La_Rioja</id>
+   <id notafter="673588800000" repl="America/Argentina/Buenos_Aires">America/Argentina/Rio_Gallegos</id>
+   <id notafter="1087704000000" repl="America/Argentina/Buenos_Aires">America/Argentina/Ushuaia</id>
    <id>America/Argentina/San_Luis</id>
   </country>
   <country code="as" default="Pacific/Pago_Pago" everutc="n">
-   <id>Pacific/Pago_Pago</id>
+   <id alts="Pacific/Samoa,US/Samoa">Pacific/Pago_Pago</id>
   </country>
   <country code="at" default="Europe/Vienna" everutc="n">
    <id>Europe/Vienna</id>
   </country>
   <country code="au" default="Australia/Sydney" everutc="n">
-   <id>Australia/Sydney</id>
-   <id notafter="796147200000">Australia/Melbourne</id>
-   <id notafter="1193500800000">Australia/Hobart</id>
-   <id notafter="37728000000">Australia/Currie</id>
-   <id>Australia/Brisbane</id>
-   <id notafter="762883200000">Australia/Lindeman</id>
+   <id alts="Australia/ACT,Australia/Canberra,Australia/NSW">Australia/Sydney</id>
+   <id notafter="796147200000" repl="Australia/Sydney" alts="Australia/Victoria">Australia/Melbourne</id>
+   <id notafter="1193500800000" repl="Australia/Sydney" alts="Australia/Tasmania">Australia/Hobart</id>
+   <id notafter="37728000000" repl="Australia/Sydney">Australia/Currie</id>
+   <id alts="Australia/Queensland">Australia/Brisbane</id>
+   <id notafter="762883200000" repl="Australia/Brisbane">Australia/Lindeman</id>
    <id>Antarctica/Macquarie</id>
-   <id>Australia/Lord_Howe</id>
-   <id>Australia/Adelaide</id>
-   <id notafter="796149000000">Australia/Broken_Hill</id>
-   <id>Australia/Darwin</id>
-   <id>Australia/Perth</id>
+   <id alts="Australia/LHI">Australia/Lord_Howe</id>
+   <id alts="Australia/South">Australia/Adelaide</id>
+   <id notafter="796149000000" repl="Australia/Adelaide" alts="Australia/Yancowinna">Australia/Broken_Hill</id>
+   <id alts="Australia/North">Australia/Darwin</id>
+   <id alts="Australia/West">Australia/Perth</id>
    <id>Australia/Eucla</id>
   </country>
   <country code="aw" default="America/Aruba" everutc="n">
@@ -91,7 +91,7 @@
    <id>America/Barbados</id>
   </country>
   <country code="bd" default="Asia/Dhaka" everutc="n">
-   <id>Asia/Dhaka</id>
+   <id alts="Asia/Dacca">Asia/Dhaka</id>
   </country>
   <country code="be" default="Europe/Brussels" everutc="n">
    <id>Europe/Brussels</id>
@@ -127,28 +127,28 @@
    <id>America/Kralendijk</id>
   </country>
   <country code="br" default="America/Noronha" everutc="n">
-   <id>America/Noronha</id>
-   <id>America/Sao_Paulo</id>
-   <id notafter="1550368800000">America/Bahia</id>
-   <id notafter="1214280000000">America/Santarem</id>
-   <id notafter="1330221600000">America/Recife</id>
-   <id notafter="972180000000">America/Fortaleza</id>
-   <id notafter="1013911200000">America/Belem</id>
-   <id notafter="824004000000">America/Maceio</id>
-   <id notafter="1361066400000">America/Araguaina</id>
-   <id>America/Manaus</id>
-   <id notafter="1550372400000">America/Cuiaba</id>
-   <id notafter="1076814000000">America/Campo_Grande</id>
-   <id notafter="761713200000">America/Porto_Velho</id>
-   <id notafter="971578800000">America/Boa_Vista</id>
-   <id>America/Rio_Branco</id>
-   <id notafter="761716800000">America/Eirunepe</id>
+   <id alts="Brazil/DeNoronha">America/Noronha</id>
+   <id alts="Brazil/East">America/Sao_Paulo</id>
+   <id notafter="1550368800000" repl="America/Sao_Paulo">America/Bahia</id>
+   <id notafter="1214280000000" repl="America/Sao_Paulo">America/Santarem</id>
+   <id notafter="1330221600000" repl="America/Sao_Paulo">America/Recife</id>
+   <id notafter="972180000000" repl="America/Sao_Paulo">America/Fortaleza</id>
+   <id notafter="1013911200000" repl="America/Sao_Paulo">America/Belem</id>
+   <id notafter="824004000000" repl="America/Sao_Paulo">America/Maceio</id>
+   <id notafter="1361066400000" repl="America/Sao_Paulo">America/Araguaina</id>
+   <id alts="Brazil/West">America/Manaus</id>
+   <id notafter="1550372400000" repl="America/Manaus">America/Cuiaba</id>
+   <id notafter="1076814000000" repl="America/Manaus">America/Campo_Grande</id>
+   <id notafter="761713200000" repl="America/Manaus">America/Porto_Velho</id>
+   <id notafter="971578800000" repl="America/Manaus">America/Boa_Vista</id>
+   <id alts="America/Porto_Acre,Brazil/Acre">America/Rio_Branco</id>
+   <id notafter="761716800000" repl="America/Rio_Branco">America/Eirunepe</id>
   </country>
   <country code="bs" default="America/Nassau" everutc="n">
    <id>America/Nassau</id>
   </country>
   <country code="bt" default="Asia/Thimphu" everutc="n">
-   <id>Asia/Thimphu</id>
+   <id alts="Asia/Thimbu">Asia/Thimphu</id>
   </country>
   <country code="bw" default="Africa/Gaborone" everutc="n">
    <id>Africa/Gaborone</id>
@@ -160,34 +160,34 @@
    <id>America/Belize</id>
   </country>
   <country code="ca" default="America/Toronto" everutc="n">
-   <id>America/Toronto</id>
-   <id>America/Vancouver</id>
-   <id>America/Edmonton</id>
-   <id>America/Winnipeg</id>
-   <id>America/Halifax</id>
-   <id>America/St_Johns</id>
-   <id notafter="1162098000000">America/Moncton</id>
-   <id notafter="57733200000">America/Glace_Bay</id>
-   <id notafter="1299996000000">America/Goose_Bay</id>
+   <id alts="America/Montreal,Canada/Eastern">America/Toronto</id>
+   <id alts="Canada/Pacific">America/Vancouver</id>
+   <id alts="Canada/Mountain">America/Edmonton</id>
+   <id alts="Canada/Central">America/Winnipeg</id>
+   <id alts="Canada/Atlantic">America/Halifax</id>
+   <id alts="Canada/Newfoundland">America/St_Johns</id>
+   <id notafter="1162098000000" repl="America/Halifax">America/Moncton</id>
+   <id notafter="57733200000" repl="America/Halifax">America/Glace_Bay</id>
+   <id notafter="1299996000000" repl="America/Halifax">America/Goose_Bay</id>
    <id>America/Blanc-Sablon</id>
-   <id notafter="120636000000">America/Thunder_Bay</id>
-   <id notafter="972802800000">America/Iqaluit</id>
-   <id notafter="89186400000">America/Nipigon</id>
-   <id notafter="796806000000">America/Pangnirtung</id>
-   <id>America/Atikokan</id>
-   <id>America/Regina</id>
-   <id notafter="73472400000">America/Swift_Current</id>
-   <id notafter="1130659200000">America/Rankin_Inlet</id>
-   <id notafter="986112000000">America/Rainy_River</id>
-   <id notafter="1173600000000">America/Resolute</id>
-   <id notafter="309945600000">America/Yellowknife</id>
-   <id notafter="1583661600000">America/Dawson_Creek</id>
-   <id notafter="84013200000">America/Creston</id>
-   <id notafter="1425808800000">America/Fort_Nelson</id>
-   <id notafter="294228000000">America/Inuvik</id>
-   <id notafter="986115600000">America/Cambridge_Bay</id>
-   <id notafter="120646800000">America/Dawson</id>
-   <id>America/Whitehorse</id>
+   <id notafter="120636000000" repl="America/Toronto">America/Thunder_Bay</id>
+   <id notafter="972802800000" repl="America/Toronto">America/Iqaluit</id>
+   <id notafter="89186400000" repl="America/Toronto">America/Nipigon</id>
+   <id notafter="796806000000" repl="America/Toronto">America/Pangnirtung</id>
+   <id alts="America/Coral_Harbour">America/Atikokan</id>
+   <id alts="Canada/Saskatchewan">America/Regina</id>
+   <id notafter="73472400000" repl="America/Winnipeg">America/Swift_Current</id>
+   <id notafter="1130659200000" repl="America/Winnipeg">America/Rankin_Inlet</id>
+   <id notafter="986112000000" repl="America/Winnipeg">America/Rainy_River</id>
+   <id notafter="1173600000000" repl="America/Winnipeg">America/Resolute</id>
+   <id notafter="309945600000" repl="America/Edmonton">America/Yellowknife</id>
+   <id notafter="1583661600000" repl="America/Edmonton">America/Dawson_Creek</id>
+   <id notafter="84013200000" repl="America/Edmonton">America/Creston</id>
+   <id notafter="1425808800000" repl="America/Edmonton">America/Fort_Nelson</id>
+   <id notafter="294228000000" repl="America/Edmonton">America/Inuvik</id>
+   <id notafter="986115600000" repl="America/Edmonton">America/Cambridge_Bay</id>
+   <id notafter="120646800000" repl="America/Edmonton">America/Dawson</id>
+   <id alts="Canada/Yukon">America/Whitehorse</id>
   </country>
   <country code="cc" default="Indian/Cocos" everutc="n">
    <id>Indian/Cocos</id>
@@ -206,22 +206,22 @@
    <id>Europe/Zurich</id>
   </country>
   <country code="ci" default="Africa/Abidjan" everutc="y">
-   <id>Africa/Abidjan</id>
+   <id alts="Africa/Timbuktu">Africa/Abidjan</id>
   </country>
   <country code="ck" default="Pacific/Rarotonga" everutc="n">
    <id>Pacific/Rarotonga</id>
   </country>
   <country code="cl" default="America/Santiago" everutc="n">
    <id>America/Punta_Arenas</id>
-   <id>America/Santiago</id>
-   <id>Pacific/Easter</id>
+   <id alts="Chile/Continental">America/Santiago</id>
+   <id alts="Chile/EasterIsland">Pacific/Easter</id>
   </country>
   <country code="cm" default="Africa/Douala" everutc="n">
    <id>Africa/Douala</id>
   </country>
   <country code="cn" default="Asia/Shanghai" defaultBoost="y" everutc="n">
-   <id>Asia/Shanghai</id>
-   <id>Asia/Urumqi</id>
+   <id alts="Asia/Chongqing,Asia/Chungking,Asia/Harbin,PRC">Asia/Shanghai</id>
+   <id alts="Asia/Kashgar">Asia/Urumqi</id>
   </country>
   <country code="co" default="America/Bogota" everutc="n">
    <id>America/Bogota</id>
@@ -230,7 +230,7 @@
    <id>America/Costa_Rica</id>
   </country>
   <country code="cu" default="America/Havana" everutc="n">
-   <id>America/Havana</id>
+   <id alts="Cuba">America/Havana</id>
   </country>
   <country code="cv" default="Atlantic/Cape_Verde" everutc="n">
    <id>Atlantic/Cape_Verde</id>
@@ -250,7 +250,7 @@
   </country>
   <country code="de" default="Europe/Berlin" everutc="n">
    <id>Europe/Berlin</id>
-   <id notafter="338950800000">Europe/Busingen</id>
+   <id notafter="338950800000" repl="Europe/Berlin">Europe/Busingen</id>
   </country>
   <country code="dj" default="Africa/Djibouti" everutc="n">
    <id>Africa/Djibouti</id>
@@ -275,7 +275,7 @@
    <id>Europe/Tallinn</id>
   </country>
   <country code="eg" default="Africa/Cairo" everutc="n">
-   <id>Africa/Cairo</id>
+   <id alts="Egypt">Africa/Cairo</id>
   </country>
   <country code="eh" default="Africa/El_Aaiun" everutc="y">
    <id>Africa/El_Aaiun</id>
@@ -285,7 +285,7 @@
   </country>
   <country code="es" default="Europe/Madrid" everutc="y">
    <id>Europe/Madrid</id>
-   <id notafter="496803600000">Africa/Ceuta</id>
+   <id notafter="496803600000" repl="Europe/Madrid">Africa/Ceuta</id>
    <id>Atlantic/Canary</id>
   </country>
   <country code="et" default="Africa/Addis_Ababa" everutc="n">
@@ -301,12 +301,12 @@
    <id>Atlantic/Stanley</id>
   </country>
   <country code="fm" default="Pacific/Pohnpei" everutc="n">
-   <id>Pacific/Pohnpei</id>
+   <id alts="Pacific/Ponape">Pacific/Pohnpei</id>
    <id>Pacific/Kosrae</id>
-   <id>Pacific/Chuuk</id>
+   <id alts="Pacific/Truk,Pacific/Yap">Pacific/Chuuk</id>
   </country>
   <country code="fo" default="Atlantic/Faroe" everutc="y">
-   <id>Atlantic/Faroe</id>
+   <id alts="Atlantic/Faeroe">Atlantic/Faroe</id>
   </country>
   <country code="fr" default="Europe/Paris" everutc="n">
    <id>Europe/Paris</id>
@@ -315,7 +315,7 @@
    <id>Africa/Libreville</id>
   </country>
   <country code="gb" default="Europe/London" everutc="y">
-   <id>Europe/London</id>
+   <id alts="Europe/Belfast,GB,GB-Eire">Europe/London</id>
   </country>
   <country code="gd" default="America/Grenada" everutc="n">
    <id>America/Grenada</id>
@@ -338,7 +338,7 @@
   <country code="gl" default="America/Nuuk" everutc="y">
    <id>America/Danmarkshavn</id>
    <id>America/Scoresbysund</id>
-   <id>America/Nuuk</id>
+   <id alts="America/Godthab">America/Nuuk</id>
    <id>America/Thule</id>
   </country>
   <country code="gm" default="Africa/Banjul" everutc="y">
@@ -372,7 +372,7 @@
    <id>America/Guyana</id>
   </country>
   <country code="hk" default="Asia/Hong_Kong" everutc="n">
-   <id>Asia/Hong_Kong</id>
+   <id alts="Hongkong">Asia/Hong_Kong</id>
   </country>
   <country code="hn" default="America/Tegucigalpa" everutc="n">
    <id>America/Tegucigalpa</id>
@@ -388,21 +388,21 @@
   </country>
   <country code="id" default="Asia/Jakarta" everutc="n">
    <id>Asia/Jayapura</id>
-   <id>Asia/Makassar</id>
+   <id alts="Asia/Ujung_Pandang">Asia/Makassar</id>
    <id>Asia/Jakarta</id>
-   <id notafter="567964800000">Asia/Pontianak</id>
+   <id notafter="567964800000" repl="Asia/Jakarta">Asia/Pontianak</id>
   </country>
   <country code="ie" default="Europe/Dublin" everutc="y">
-   <id>Europe/Dublin</id>
+   <id alts="Eire">Europe/Dublin</id>
   </country>
   <country code="il" default="Asia/Jerusalem" everutc="n">
-   <id>Asia/Jerusalem</id>
+   <id alts="Asia/Tel_Aviv,Israel">Asia/Jerusalem</id>
   </country>
   <country code="im" default="Europe/Isle_of_Man" everutc="y">
    <id>Europe/Isle_of_Man</id>
   </country>
   <country code="in" default="Asia/Kolkata" everutc="n">
-   <id>Asia/Kolkata</id>
+   <id alts="Asia/Calcutta">Asia/Kolkata</id>
   </country>
   <country code="io" default="Indian/Chagos" everutc="n">
    <id>Indian/Chagos</id>
@@ -411,10 +411,10 @@
    <id>Asia/Baghdad</id>
   </country>
   <country code="ir" default="Asia/Tehran" everutc="n">
-   <id>Asia/Tehran</id>
+   <id alts="Iran">Asia/Tehran</id>
   </country>
   <country code="is" default="Atlantic/Reykjavik" everutc="y">
-   <id>Atlantic/Reykjavik</id>
+   <id alts="Iceland">Atlantic/Reykjavik</id>
   </country>
   <country code="it" default="Europe/Rome" everutc="n">
    <id>Europe/Rome</id>
@@ -423,16 +423,16 @@
    <id>Europe/Jersey</id>
   </country>
   <country code="jm" default="America/Jamaica" everutc="n">
-   <id>America/Jamaica</id>
+   <id alts="Jamaica">America/Jamaica</id>
   </country>
   <country code="jo" default="Asia/Amman" everutc="n">
    <id>Asia/Amman</id>
   </country>
   <country code="jp" default="Asia/Tokyo" everutc="n">
-   <id>Asia/Tokyo</id>
+   <id alts="Japan">Asia/Tokyo</id>
   </country>
   <country code="ke" default="Africa/Nairobi" everutc="n">
-   <id>Africa/Nairobi</id>
+   <id alts="Africa/Asmera">Africa/Nairobi</id>
   </country>
   <country code="kg" default="Asia/Bishkek" everutc="n">
    <id>Asia/Bishkek</id>
@@ -455,7 +455,7 @@
    <id>Asia/Pyongyang</id>
   </country>
   <country code="kr" default="Asia/Seoul" everutc="n">
-   <id>Asia/Seoul</id>
+   <id alts="ROK">Asia/Seoul</id>
   </country>
   <country code="kw" default="Asia/Kuwait" everutc="n">
    <id>Asia/Kuwait</id>
@@ -465,12 +465,12 @@
   </country>
   <country code="kz" default="Asia/Almaty" everutc="n">
    <id>Asia/Almaty</id>
-   <id notafter="1099170000000">Asia/Qostanay</id>
+   <id notafter="1099170000000" repl="Asia/Almaty">Asia/Qostanay</id>
    <id>Asia/Oral</id>
-   <id notafter="1099173600000">Asia/Aqtau</id>
-   <id notafter="1545328800000">Asia/Qyzylorda</id>
-   <id notafter="1545328800000">Asia/Aqtobe</id>
-   <id notafter="922572000000">Asia/Atyrau</id>
+   <id notafter="1099173600000" repl="Asia/Oral">Asia/Aqtau</id>
+   <id notafter="1545328800000" repl="Asia/Oral">Asia/Qyzylorda</id>
+   <id notafter="1545328800000" repl="Asia/Oral">Asia/Aqtobe</id>
+   <id notafter="922572000000" repl="Asia/Oral">Asia/Atyrau</id>
   </country>
   <country code="la" default="Asia/Vientiane" everutc="n">
    <id>Asia/Vientiane</id>
@@ -503,7 +503,7 @@
    <id>Europe/Riga</id>
   </country>
   <country code="ly" default="Africa/Tripoli" everutc="n">
-   <id>Africa/Tripoli</id>
+   <id alts="Libya">Africa/Tripoli</id>
   </country>
   <country code="ma" default="Africa/Casablanca" everutc="y">
    <id>Africa/Casablanca</id>
@@ -512,7 +512,7 @@
    <id>Europe/Monaco</id>
   </country>
   <country code="md" default="Europe/Chisinau" everutc="n">
-   <id>Europe/Chisinau</id>
+   <id alts="Europe/Tiraspol">Europe/Chisinau</id>
   </country>
   <country code="me" default="Europe/Podgorica" everutc="n">
    <id>Europe/Podgorica</id>
@@ -525,7 +525,7 @@
   </country>
   <country code="mh" default="Pacific/Majuro" everutc="n">
    <id>Pacific/Majuro</id>
-   <id notafter="745934400000">Pacific/Kwajalein</id>
+   <id notafter="745934400000" repl="Pacific/Majuro" alts="Kwajalein">Pacific/Kwajalein</id>
   </country>
   <country code="mk" default="Europe/Skopje" everutc="n">
    <id>Europe/Skopje</id>
@@ -534,15 +534,15 @@
    <id>Africa/Bamako</id>
   </country>
   <country code="mm" default="Asia/Yangon" everutc="n">
-   <id>Asia/Yangon</id>
+   <id alts="Asia/Rangoon">Asia/Yangon</id>
   </country>
   <country code="mn" default="Asia/Ulaanbaatar" everutc="n">
    <id>Asia/Choibalsan</id>
-   <id>Asia/Ulaanbaatar</id>
+   <id alts="Asia/Ulan_Bator">Asia/Ulaanbaatar</id>
    <id>Asia/Hovd</id>
   </country>
   <country code="mo" default="Asia/Macau" everutc="n">
-   <id>Asia/Macau</id>
+   <id alts="Asia/Macao">Asia/Macau</id>
   </country>
   <country code="mp" default="Pacific/Saipan" everutc="n">
    <id>Pacific/Saipan</id>
@@ -569,21 +569,21 @@
    <id>Africa/Blantyre</id>
   </country>
   <country code="mx" default="America/Mexico_City" everutc="n">
-   <id>America/Mexico_City</id>
-   <id notafter="407653200000">America/Merida</id>
-   <id notafter="594198000000">America/Monterrey</id>
-   <id notafter="1270371600000">America/Bahia_Banderas</id>
+   <id alts="Mexico/General">America/Mexico_City</id>
+   <id notafter="407653200000" repl="America/Mexico_City">America/Merida</id>
+   <id notafter="594198000000" repl="America/Mexico_City">America/Monterrey</id>
+   <id notafter="1270371600000" repl="America/Mexico_City">America/Bahia_Banderas</id>
    <id>America/Matamoros</id>
    <id>America/Cancun</id>
    <id>America/Chihuahua</id>
-   <id notafter="891766800000">America/Mazatlan</id>
+   <id notafter="891766800000" repl="America/Chihuahua" alts="Mexico/BajaSur">America/Mazatlan</id>
    <id>America/Hermosillo</id>
    <id>America/Ojinaga</id>
-   <id>America/Tijuana</id>
+   <id alts="America/Ensenada,America/Santa_Isabel,Mexico/BajaNorte">America/Tijuana</id>
   </country>
   <country code="my" default="Asia/Kuala_Lumpur" everutc="n">
    <id>Asia/Kuala_Lumpur</id>
-   <id notafter="378664200000">Asia/Kuching</id>
+   <id notafter="378664200000" repl="Asia/Kuala_Lumpur">Asia/Kuching</id>
   </country>
   <country code="mz" default="Africa/Maputo" everutc="n">
    <id>Africa/Maputo</id>
@@ -610,10 +610,10 @@
    <id>Europe/Amsterdam</id>
   </country>
   <country code="no" default="Europe/Oslo" everutc="n">
-   <id>Europe/Oslo</id>
+   <id alts="Atlantic/Jan_Mayen">Europe/Oslo</id>
   </country>
   <country code="np" default="Asia/Kathmandu" everutc="n">
-   <id>Asia/Kathmandu</id>
+   <id alts="Asia/Katmandu">Asia/Kathmandu</id>
   </country>
   <country code="nr" default="Pacific/Nauru" everutc="n">
    <id>Pacific/Nauru</id>
@@ -622,8 +622,8 @@
    <id>Pacific/Niue</id>
   </country>
   <country code="nz" default="Pacific/Auckland" defaultBoost="y" everutc="n">
-   <id>Pacific/Auckland</id>
-   <id>Pacific/Chatham</id>
+   <id alts="Antarctica/South_Pole,NZ">Pacific/Auckland</id>
+   <id alts="NZ-CHAT">Pacific/Chatham</id>
   </country>
   <country code="om" default="Asia/Muscat" everutc="n">
    <id>Asia/Muscat</id>
@@ -650,7 +650,7 @@
    <id>Asia/Karachi</id>
   </country>
   <country code="pl" default="Europe/Warsaw" everutc="n">
-   <id>Europe/Warsaw</id>
+   <id alts="Poland">Europe/Warsaw</id>
   </country>
   <country code="pm" default="America/Miquelon" everutc="n">
    <id>America/Miquelon</id>
@@ -663,11 +663,11 @@
   </country>
   <country code="ps" default="Asia/Gaza" everutc="n">
    <id>Asia/Hebron</id>
-   <id notafter="1317330000000">Asia/Gaza</id>
+   <id notafter="1317330000000" repl="Asia/Hebron">Asia/Gaza</id>
   </country>
   <country code="pt" default="Europe/Lisbon" everutc="y">
-   <id>Europe/Lisbon</id>
-   <id notafter="828234000000">Atlantic/Madeira</id>
+   <id alts="Portugal">Europe/Lisbon</id>
+   <id notafter="828234000000" repl="Europe/Lisbon">Atlantic/Madeira</id>
    <id>Atlantic/Azores</id>
   </country>
   <country code="pw" default="Pacific/Palau" everutc="n">
@@ -695,24 +695,24 @@
    <id>Asia/Sakhalin</id>
    <id>Asia/Srednekolymsk</id>
    <id>Asia/Vladivostok</id>
-   <id notafter="1315828800000">Asia/Ust-Nera</id>
+   <id notafter="1315828800000" repl="Asia/Vladivostok">Asia/Ust-Nera</id>
    <id>Asia/Chita</id>
-   <id notafter="1459015200000">Asia/Yakutsk</id>
-   <id notafter="1315832400000">Asia/Khandyga</id>
+   <id notafter="1459015200000" repl="Asia/Chita">Asia/Yakutsk</id>
+   <id notafter="1315832400000" repl="Asia/Chita">Asia/Khandyga</id>
    <id>Asia/Irkutsk</id>
    <id>Asia/Krasnoyarsk</id>
-   <id notafter="1459022400000">Asia/Novokuznetsk</id>
+   <id notafter="1459022400000" repl="Asia/Krasnoyarsk">Asia/Novokuznetsk</id>
    <id>Asia/Novosibirsk</id>
    <id>Asia/Barnaul</id>
-   <id notafter="1464465600000">Asia/Tomsk</id>
+   <id notafter="1464465600000" repl="Asia/Barnaul">Asia/Tomsk</id>
    <id>Asia/Omsk</id>
    <id>Asia/Yekaterinburg</id>
    <id>Europe/Samara</id>
    <id>Europe/Saratov</id>
-   <id notafter="1480806000000">Europe/Ulyanovsk</id>
-   <id notafter="701823600000">Europe/Astrakhan</id>
+   <id notafter="1480806000000" repl="Europe/Saratov">Europe/Ulyanovsk</id>
+   <id notafter="701823600000" repl="Europe/Saratov">Europe/Astrakhan</id>
    <id>Europe/Volgograd</id>
-   <id>Europe/Moscow</id>
+   <id alts="W-SU">Europe/Moscow</id>
    <id>Europe/Kirov</id>
    <id>Europe/Kaliningrad</id>
   </country>
@@ -735,7 +735,7 @@
    <id>Europe/Stockholm</id>
   </country>
   <country code="sg" default="Asia/Singapore" everutc="n">
-   <id>Asia/Singapore</id>
+   <id alts="Singapore">Asia/Singapore</id>
   </country>
   <country code="sh" default="Atlantic/St_Helena" everutc="y">
    <id>Atlantic/St_Helena</id>
@@ -807,7 +807,7 @@
    <id>Asia/Dili</id>
   </country>
   <country code="tm" default="Asia/Ashgabat" everutc="n">
-   <id>Asia/Ashgabat</id>
+   <id alts="Asia/Ashkhabad">Asia/Ashgabat</id>
   </country>
   <country code="tn" default="Africa/Tunis" everutc="n">
    <id>Africa/Tunis</id>
@@ -816,24 +816,24 @@
    <id>Pacific/Tongatapu</id>
   </country>
   <country code="tr" default="Europe/Istanbul" everutc="n">
-   <id>Europe/Istanbul</id>
+   <id alts="Turkey">Europe/Istanbul</id>
   </country>
   <country code="tt" default="America/Port_of_Spain" everutc="n">
-   <id>America/Port_of_Spain</id>
+   <id alts="America/Virgin">America/Port_of_Spain</id>
   </country>
   <country code="tv" default="Pacific/Funafuti" everutc="n">
    <id>Pacific/Funafuti</id>
   </country>
   <country code="tw" default="Asia/Taipei" everutc="n">
-   <id>Asia/Taipei</id>
+   <id alts="ROC">Asia/Taipei</id>
   </country>
   <country code="tz" default="Africa/Dar_es_Salaam" everutc="n">
    <id>Africa/Dar_es_Salaam</id>
   </country>
   <country code="ua" default="Europe/Kiev" everutc="n">
    <id>Europe/Kiev</id>
-   <id notafter="686102400000">Europe/Zaporozhye</id>
-   <id notafter="686091600000">Europe/Uzhgorod</id>
+   <id notafter="686102400000" repl="Europe/Kiev">Europe/Zaporozhye</id>
+   <id notafter="686091600000" repl="Europe/Kiev">Europe/Uzhgorod</id>
    <id picker="n">Europe/Simferopol</id>
   </country>
   <country code="ug" default="Africa/Kampala" everutc="n">
@@ -844,42 +844,42 @@
    <id>Pacific/Midway</id>
   </country>
   <country code="us" default="America/New_York" everutc="n">
-   <id>America/New_York</id>
-   <id notafter="152089200000">America/Kentucky/Louisville</id>
-   <id notafter="167814000000">America/Detroit</id>
-   <id notafter="1130652000000">America/Indiana/Indianapolis</id>
-   <id notafter="1194159600000">America/Indiana/Vincennes</id>
-   <id notafter="972802800000">America/Kentucky/Monticello</id>
-   <id notafter="247042800000">America/Indiana/Petersburg</id>
-   <id notafter="1173600000000">America/Indiana/Winamac</id>
-   <id notafter="89186400000">America/Indiana/Vevay</id>
-   <id notafter="183535200000">America/Indiana/Marengo</id>
-   <id>America/Chicago</id>
-   <id notafter="104918400000">America/Menominee</id>
-   <id notafter="1143964800000">America/Indiana/Tell_City</id>
-   <id notafter="688546800000">America/Indiana/Knox</id>
-   <id notafter="1289116800000">America/North_Dakota/Beulah</id>
-   <id notafter="1067155200000">America/North_Dakota/New_Salem</id>
-   <id notafter="720000000000">America/North_Dakota/Center</id>
-   <id>America/Denver</id>
-   <id>America/Phoenix</id>
-   <id notafter="129114000000">America/Boise</id>
-   <id>America/Los_Angeles</id>
-   <id>America/Anchorage</id>
-   <id notafter="436359600000">America/Juneau</id>
-   <id notafter="341402400000">America/Sitka</id>
-   <id notafter="436363200000">America/Nome</id>
-   <id notafter="1547978400000">America/Metlakatla</id>
-   <id notafter="436356000000">America/Yakutat</id>
-   <id>Pacific/Honolulu</id>
-   <id>America/Adak</id>
+   <id alts="US/Eastern">America/New_York</id>
+   <id notafter="152089200000" repl="America/New_York" alts="America/Louisville">America/Kentucky/Louisville</id>
+   <id notafter="167814000000" repl="America/New_York" alts="US/Michigan">America/Detroit</id>
+   <id notafter="1130652000000" repl="America/New_York" alts="America/Fort_Wayne,America/Indianapolis,US/East-Indiana">America/Indiana/Indianapolis</id>
+   <id notafter="1194159600000" repl="America/New_York">America/Indiana/Vincennes</id>
+   <id notafter="972802800000" repl="America/New_York">America/Kentucky/Monticello</id>
+   <id notafter="247042800000" repl="America/New_York">America/Indiana/Petersburg</id>
+   <id notafter="1173600000000" repl="America/New_York">America/Indiana/Winamac</id>
+   <id notafter="89186400000" repl="America/New_York">America/Indiana/Vevay</id>
+   <id notafter="183535200000" repl="America/New_York">America/Indiana/Marengo</id>
+   <id alts="US/Central">America/Chicago</id>
+   <id notafter="104918400000" repl="America/Chicago">America/Menominee</id>
+   <id notafter="1143964800000" repl="America/Chicago">America/Indiana/Tell_City</id>
+   <id notafter="688546800000" repl="America/Chicago" alts="America/Knox_IN,US/Indiana-Starke">America/Indiana/Knox</id>
+   <id notafter="1289116800000" repl="America/Chicago">America/North_Dakota/Beulah</id>
+   <id notafter="1067155200000" repl="America/Chicago">America/North_Dakota/New_Salem</id>
+   <id notafter="720000000000" repl="America/Chicago">America/North_Dakota/Center</id>
+   <id alts="America/Shiprock,Navajo,US/Mountain">America/Denver</id>
+   <id alts="US/Arizona">America/Phoenix</id>
+   <id notafter="129114000000" repl="America/Phoenix">America/Boise</id>
+   <id alts="US/Pacific">America/Los_Angeles</id>
+   <id alts="US/Alaska">America/Anchorage</id>
+   <id notafter="436359600000" repl="America/Anchorage">America/Juneau</id>
+   <id notafter="341402400000" repl="America/Anchorage">America/Sitka</id>
+   <id notafter="436363200000" repl="America/Anchorage">America/Nome</id>
+   <id notafter="1547978400000" repl="America/Anchorage">America/Metlakatla</id>
+   <id notafter="436356000000" repl="America/Anchorage">America/Yakutat</id>
+   <id alts="Pacific/Johnston,US/Hawaii">Pacific/Honolulu</id>
+   <id alts="America/Atka,US/Aleutian">America/Adak</id>
   </country>
   <country code="uy" default="America/Montevideo" everutc="n">
    <id>America/Montevideo</id>
   </country>
   <country code="uz" default="Asia/Tashkent" everutc="n">
    <id>Asia/Tashkent</id>
-   <id notafter="670366800000">Asia/Samarkand</id>
+   <id notafter="670366800000" repl="Asia/Tashkent">Asia/Samarkand</id>
   </country>
   <country code="va" default="Europe/Vatican" everutc="n">
    <id>Europe/Vatican</id>
@@ -897,7 +897,7 @@
    <id>America/St_Thomas</id>
   </country>
   <country code="vn" default="Asia/Ho_Chi_Minh" everutc="n">
-   <id>Asia/Ho_Chi_Minh</id>
+   <id alts="Asia/Saigon">Asia/Ho_Chi_Minh</id>
   </country>
   <country code="vu" default="Pacific/Efate" everutc="n">
    <id>Pacific/Efate</id>
diff --git a/testing/data/test3/output_data/distro/distro.zip b/testing/data/test3/output_data/distro/distro.zip
index c9a74cb..3c1e3a2 100644
--- a/testing/data/test3/output_data/distro/distro.zip
+++ b/testing/data/test3/output_data/distro/distro.zip
Binary files differ
diff --git a/testing/data/test3/output_data/iana/tzdata b/testing/data/test3/output_data/iana/tzdata
index c5a28a4..e60fb5e 100644
--- a/testing/data/test3/output_data/iana/tzdata
+++ b/testing/data/test3/output_data/iana/tzdata
Binary files differ
diff --git a/testing/data/test3/output_data/version/tz_version b/testing/data/test3/output_data/version/tz_version
index e1e8f45..b843d8a 100644
--- a/testing/data/test3/output_data/version/tz_version
+++ b/testing/data/test3/output_data/version/tz_version
@@ -1 +1 @@
-004.001|2030a|001
\ No newline at end of file
+005.001|2030a|001
\ No newline at end of file
diff --git a/testing/src/main/java/libcore/timezone/testing/ZoneInfoTestHelper.java b/testing/src/main/java/libcore/timezone/testing/ZoneInfoTestHelper.java
index 224b193..aa1c253 100644
--- a/testing/src/main/java/libcore/timezone/testing/ZoneInfoTestHelper.java
+++ b/testing/src/main/java/libcore/timezone/testing/ZoneInfoTestHelper.java
@@ -222,10 +222,9 @@
         // A list is used in preference to a Map to allow simulation of badly ordered / duplicate
         // IDs.
         private List<ZicDatum> zicData = new ArrayList<>();
-        private String zoneTab;
         private Integer indexOffsetOverride;
         private Integer dataOffsetOverride;
-        private Integer zoneTabOffsetOverride;
+        private Integer finalOffsetOverride;
 
         public TzDataBuilder() {}
 
@@ -245,8 +244,8 @@
             return this;
         }
 
-        public TzDataBuilder setZoneTabOffsetOverride(int zoneTabOffset) {
-            this.zoneTabOffsetOverride = zoneTabOffset;
+        public TzDataBuilder setFinalOffsetOverride(int finalOffset) {
+            this.finalOffsetOverride = finalOffset;
             return this;
         }
 
@@ -259,15 +258,9 @@
             return this;
         }
 
-        public TzDataBuilder setZoneTab(String zoneTab) {
-            this.zoneTab = zoneTab;
-            return this;
-        }
-
         public TzDataBuilder initializeToValid() {
             setHeaderMagic("tzdata9999a");
             addZicData("Europe/Elbonia", new ZicDataBuilder().initializeToValid().build());
-            setZoneTab("ZoneTab data");
             return this;
         }
 
@@ -288,7 +281,7 @@
             writeInt(baos, 0);
             int dataOffsetOffset = baos.size();
             writeInt(baos, 0);
-            int zoneTabOffsetOffset = baos.size();
+            int finalOffsetOffset = baos.size();
             writeInt(baos, 0);
 
             // Construct the data section in advance, so we know the offsets.
@@ -323,18 +316,15 @@
             int dataOffset = baos.size();
             writeByteArray(baos, dataBytes.toByteArray());
 
-            // Write the zoneTab section.
-            int zoneTabOffset = baos.size();
-            byte[] zoneTabBytes = zoneTab.getBytes(StandardCharsets.US_ASCII);
-            writeByteArray(baos, zoneTabBytes);
+            int finalOffset = baos.size();
 
             byte[] bytes = baos.toByteArray();
             setInt(bytes, indexOffsetOffset,
                     indexOffsetOverride != null ? indexOffsetOverride : indexOffset);
             setInt(bytes, dataOffsetOffset,
                     dataOffsetOverride != null ? dataOffsetOverride : dataOffset);
-            setInt(bytes, zoneTabOffsetOffset,
-                    zoneTabOffsetOverride != null ? zoneTabOffsetOverride : zoneTabOffset);
+            setInt(bytes, finalOffsetOffset,
+                    finalOffsetOverride != null ? finalOffsetOverride : finalOffset);
             return bytes;
         }
 
diff --git a/update-tzdata.py b/update-tzdata.py
index ee370c1..9cf565b 100755
--- a/update-tzdata.py
+++ b/update-tzdata.py
@@ -72,15 +72,30 @@
   for line in open(zic_input_file):
     fields = line.split()
     if fields:
-      if fields[0] == 'Link':
-        links.append('%s %s %s' % (fields[0], fields[1], fields[2]))
-        zones.append(fields[2])
-      elif fields[0] == 'Zone':
-        zones.append(fields[1])
-  zones.sort()
+      line_type = fields[0]
+      if line_type == 'Link':
+        # Each "Link" line requires the creation of a link from an old tz ID to
+        # a new tz ID, and implies the existence of a zone with the old tz ID.
+        #
+        # IANA terminology:
+        # TARGET = the new tz ID, LINK-NAME = the old tz ID
+        target = fields[1]
+        link_name = fields[2]
+        links.append('Link %s %s' % (target, link_name))
+        zones.append('Zone %s' % link_name)
+      elif line_type == 'Zone':
+        # Each "Zone" line indicates the existence of a tz ID.
+        #
+        # IANA terminology:
+        # NAME is the tz ID, other fields like STDOFF, RULES, FORMAT,[UNTIL] are
+        # ignored.
+        name = fields[1]
+        zones.append('Zone %s' % name)
 
   zone_compactor_setup_file = '%s/setup' % tmp_dir
   setup = open(zone_compactor_setup_file, 'w')
+
+  # Ordering requirement from ZoneCompactor: Links must come first.
   for link in sorted(set(links)):
     setup.write('%s\n' % link)
   for zone in sorted(set(zones)):
@@ -129,7 +144,8 @@
   iana_zic_data_version = GetIanaVersion(iana_zic_data_tar_file)
 
   print('Found IANA zic release %s/%s in %s/%s ...' \
-      % (iana_zic_code_version, iana_zic_data_version, iana_zic_code_tar_file, iana_zic_data_tar_file))
+      % (iana_zic_code_version, iana_zic_data_version, iana_zic_code_tar_file,
+         iana_zic_data_tar_file))
 
   zic_build_dir = '%s/zic' % tmp_dir
   ExtractTarFile(iana_zic_code_tar_file, zic_build_dir)
@@ -166,28 +182,28 @@
   tzdatautil.InvokeSoong(android_build_top, ['zone_compactor'])
 
   # Create args for ZoneCompactor
-  zone_tab_file = '%s/zone.tab' % extracted_iana_data_dir
   header_string = 'tzdata%s' % iana_data_version
 
   print('Executing ZoneCompactor...')
   command = '%s/bin/zone_compactor' % android_host_out
   iana_output_data_dir = '%s/iana' % timezone_output_data_dir
-  subprocess.check_call([command, zone_compactor_setup_file, zic_output_dir, zone_tab_file,
-                         iana_output_data_dir, header_string])
+  subprocess.check_call([command, zone_compactor_setup_file, zic_output_dir, iana_output_data_dir,
+                         header_string])
 
 
-def BuildTzlookup(iana_data_dir):
+def BuildTzlookupAndTzIds(iana_data_dir):
   countryzones_source_file = '%s/android/countryzones.txt' % timezone_input_data_dir
   tzlookup_dest_file = '%s/android/tzlookup.xml' % timezone_output_data_dir
+  tzids_dest_file = '%s/android/tzids.prototxt' % timezone_output_data_dir
 
-  print('Calling TzLookupGenerator to create tzlookup.xml...')
+  print('Calling TzLookupGenerator to create tzlookup.xml / tzids.prototxt...')
   tzdatautil.InvokeSoong(android_build_top, ['tzlookup_generator'])
 
   zone_tab_file = '%s/zone.tab' % iana_data_dir
   backward_file = '%s/backward' % iana_data_dir
   command = '%s/bin/tzlookup_generator' % android_host_out
   subprocess.check_call([command, countryzones_source_file, zone_tab_file, backward_file,
-                         tzlookup_dest_file])
+                         tzlookup_dest_file, tzids_dest_file])
 
 
 def BuildTelephonylookup():
@@ -236,6 +252,7 @@
 def main():
   print('Source data file structure: %s' % timezone_input_data_dir)
   print('Source tools file structure: %s' % timezone_input_tools_dir)
+  print('Intermediate / working dir: %s' % tmp_dir)
   print('Output data file structure: %s' % timezone_output_data_dir)
 
   iana_input_data_dir = '%s/iana' % timezone_input_data_dir
@@ -254,7 +271,9 @@
   iana_data_dir = '%s/iana_data' % tmp_dir
   ExtractTarFile(iana_data_tar_file, iana_data_dir)
   BuildTzdata(zic_binary_file, iana_data_dir, iana_data_version)
-  BuildTzlookup(iana_data_dir)
+
+  BuildTzlookupAndTzIds(iana_data_dir)
+
   BuildTelephonylookup()
 
   # Create a distro file and version file from the output from prior stages.