Implement IcuZoneRulesProvider.

Implement IcuZoneRulesProvider to provide ZoneRules for java.time using
the data/API of ICU4J.

Modified artrun-testng to optionally take the name of the testng.xml
file and provide testng-time.xml file that lists all upstream tests we
imported. Also update artrun to correct list of boot dexjars.

Change ZoneRulesProvider.java to a non-JavaDoc file to avoid exposing it
as public API. Remove mention of ZoneRulesProvider from ZoneRules
JavaDoc. Removed TzdbZoneRulesProvider, which is not used on Android.

Bug: 28832222
Test: ran java.time testng changes (artrun-testng testng-time.xml) and
    IcuZoneRulesProviderTest

Change-Id: Ic24454f443ac8000fc50c2c2bddd6f28fc25bc0e
diff --git a/luni/src/test/java/libcore/java/time/zone/IcuZoneRulesProviderTest.java b/luni/src/test/java/libcore/java/time/zone/IcuZoneRulesProviderTest.java
new file mode 100644
index 0000000..c3c0f50
--- /dev/null
+++ b/luni/src/test/java/libcore/java/time/zone/IcuZoneRulesProviderTest.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2016 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 libcore.java.time.zone;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import android.icu.util.BasicTimeZone;
+import android.icu.util.TimeZone;
+import android.icu.util.TimeZoneRule;
+import android.icu.util.TimeZoneTransition;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+import java.time.zone.ZoneRulesProvider;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Test the {@link java.time.zone.IcuZoneRulesProvider}.
+ *
+ * It is indirectly tested via static methods in {@link ZoneRulesProvider} as all the relevant
+ * methods are protected. This test verifies that the rules returned by that provider behave
+ * equivalently to the ICU rules from which they are created.
+ */
+@RunWith(Parameterized.class)
+public class IcuZoneRulesProviderTest {
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<String> getZoneIds() {
+        Set<String> availableZoneIds = ZoneRulesProvider.getAvailableZoneIds();
+        assertFalse("no zones returned", availableZoneIds.isEmpty());
+        return availableZoneIds;
+    }
+
+    private final String zoneId;
+
+    public IcuZoneRulesProviderTest(final String zoneId) {
+        this.zoneId = zoneId;
+    }
+
+    /**
+     * Verifies that ICU and java.time return the same transitions before and after a pre-selected
+     * set of instants in time.
+     */
+    @Test
+    public void testTransitionsNearInstants() {
+        // An arbitrary set of instants at which to test the offsets in both implementations.
+        Instant[] instants = new Instant[] {
+                LocalDateTime.of(1900, Month.DECEMBER, 24, 12, 0).toInstant(ZoneOffset.UTC),
+                LocalDateTime.of(1970, Month.JANUARY, 1, 2, 3).toInstant(ZoneOffset.UTC),
+                LocalDateTime.of(1980, Month.FEBRUARY, 4, 5, 6).toInstant(ZoneOffset.UTC),
+                LocalDateTime.of(1990, Month.MARCH, 7, 8, 9).toInstant(ZoneOffset.UTC),
+                LocalDateTime.of(2000, Month.APRIL, 10, 11, 12).toInstant(ZoneOffset.UTC),
+                LocalDateTime.of(2016, Month.MAY, 13, 14, 15).toInstant(ZoneOffset.UTC),
+                LocalDateTime.of(2020, Month.JUNE, 16, 17, 18).toInstant(ZoneOffset.UTC),
+                LocalDateTime.of(2100, Month.JULY, 19, 20, 21).toInstant(ZoneOffset.UTC),
+                // yes, adding "now" makes the test time-dependent, but it also ensures that future
+                // updates don't break on the then-current date.
+                Instant.now()
+        };
+        // Coincidentally this test verifies that all zones can be converted to ZoneRules and
+        // don't violate any of the assumptions of IcuZoneRulesProvider.
+        ZoneRules rules = ZoneRulesProvider.getRules(zoneId, false);
+        BasicTimeZone timeZone = (BasicTimeZone) TimeZone.getTimeZone(zoneId);
+
+        int[] icuOffsets = new int[2];
+        for (Instant instant : instants) {
+            ZoneOffset offset = rules.getOffset(instant);
+            Duration daylightSavings = rules.getDaylightSavings(instant);
+            timeZone.getOffset(instant.toEpochMilli(), false, icuOffsets);
+
+            assertEquals("total offset for " + zoneId + " at " + instant,
+                    icuOffsets[1] + icuOffsets[0], offset.getTotalSeconds() * 1000);
+            assertEquals("dst offset for " + zoneId + " at " + instant,
+                    icuOffsets[1], daylightSavings.toMillis());
+
+            ZoneOffsetTransition jtTrans;
+            TimeZoneTransition icuTrans;
+
+            jtTrans = rules.nextTransition(instant);
+            icuTrans = timeZone.getNextTransition(instant.toEpochMilli(), false);
+            while (isIcuOnlyTransition(icuTrans)) {
+                icuTrans = timeZone.getNextTransition(icuTrans.getTime(), false);
+            }
+            assertEquivalent(icuTrans, jtTrans);
+
+            jtTrans = rules.previousTransition(instant);
+            icuTrans = timeZone.getPreviousTransition(instant.toEpochMilli(), false);
+            // Find previous "real" transition.
+            while (isIcuOnlyTransition(icuTrans)) {
+                icuTrans = timeZone.getPreviousTransition(icuTrans.getTime(), false);
+            }
+            assertEquivalent(icuTrans, jtTrans);
+        }
+    }
+
+    /**
+     * Verifies that ICU and java.time rules return the same transitions between 1900 and 2100.
+     */
+    @Test
+    public void testAllTransitions() {
+        final Instant start = LocalDateTime.of(1900, Month.JANUARY, 1, 12, 0)
+                .toInstant(ZoneOffset.UTC);
+        // Many timezones have ongoing DST changes, so they would generate transitions endlessly.
+        // Pick a far-future end date to stop comparing in that case.
+        final Instant end = LocalDateTime.of(2100, Month.DECEMBER, 31, 12, 0)
+                .toInstant(ZoneOffset.UTC);
+
+        ZoneRules rules = ZoneRulesProvider.getRules(zoneId, false);
+        BasicTimeZone timeZone = (BasicTimeZone) TimeZone.getTimeZone(zoneId);
+
+        Instant instant = start;
+        while (instant.isBefore(end)) {
+            ZoneOffsetTransition jtTrans;
+            TimeZoneTransition icuTrans;
+
+            jtTrans = rules.nextTransition(instant);
+            icuTrans = timeZone.getNextTransition(instant.toEpochMilli(), false);
+            while (isIcuOnlyTransition(icuTrans)) {
+                icuTrans = timeZone.getNextTransition(icuTrans.getTime(), false);
+            }
+            assertEquivalent(icuTrans, jtTrans);
+            if (jtTrans == null) {
+                break;
+            }
+            instant = jtTrans.getInstant();
+        }
+    }
+
+    /**
+     * Returns {@code true} iff this transition will only be returned by ICU code.
+     * ICU reports "no-op" transitions where the raw offset and the dst savings
+     * change by the same absolute value in opposite directions, java.time doesn't
+     * return them, so find the next "real" transition.
+     */
+    private static boolean isIcuOnlyTransition(TimeZoneTransition transition) {
+        if (transition == null) {
+            return false;
+        }
+        return transition.getFrom().getRawOffset() + transition.getFrom().getDSTSavings()
+                == transition.getTo().getRawOffset() + transition.getTo().getDSTSavings();
+    }
+
+    /**
+     * Asserts that the ICU {@link TimeZoneTransition} is equivalent to the java.time {@link
+     * ZoneOffsetTransition}.
+     */
+    private static void assertEquivalent(
+            TimeZoneTransition icuTransition, ZoneOffsetTransition jtTransition) {
+        if (icuTransition == null) {
+            assertNull(jtTransition);
+            return;
+        }
+        assertEquals("time of transition",
+                Instant.ofEpochMilli(icuTransition.getTime()), jtTransition.getInstant());
+        TimeZoneRule from = icuTransition.getFrom();
+        TimeZoneRule to = icuTransition.getTo();
+        assertEquals("offset before",
+                (from.getDSTSavings() + from.getRawOffset()) / 1000,
+                jtTransition.getOffsetBefore().getTotalSeconds());
+        assertEquals("offset after",
+                (to.getDSTSavings() + to.getRawOffset()) / 1000,
+                jtTransition.getOffsetAfter().getTotalSeconds());
+    }
+}
diff --git a/ojluni/src/main/java/java/time/zone/IcuZoneRulesProvider.java b/ojluni/src/main/java/java/time/zone/IcuZoneRulesProvider.java
new file mode 100644
index 0000000..e329eaf
--- /dev/null
+++ b/ojluni/src/main/java/java/time/zone/IcuZoneRulesProvider.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2016 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 java.time.zone;
+
+import android.icu.impl.OlsonTimeZone;
+import android.icu.util.AnnualTimeZoneRule;
+import android.icu.util.DateTimeRule;
+import android.icu.util.InitialTimeZoneRule;
+import android.icu.util.TimeZone;
+import android.icu.util.TimeZoneRule;
+import android.icu.util.TimeZoneTransition;
+import java.time.DayOfWeek;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+import libcore.util.BasicLruCache;
+
+/**
+ * A ZoneRulesProvider that generates rules from ICU4J TimeZones.
+ * This provider ensures that classes in {@link java.time} use the same time zone information
+ * as ICU4J.
+ */
+public class IcuZoneRulesProvider extends ZoneRulesProvider {
+
+    // Arbitrary upper limit to number of transitions including the final rules.
+    private static final int MAX_TRANSITIONS = 10000;
+
+    private static final int SECONDS_IN_DAY = 24 * 60 * 60;
+
+    private final BasicLruCache<String, ZoneRules> cache = new ZoneRulesCache(8);
+
+    @Override
+    protected Set<String> provideZoneIds() {
+        return new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs()));
+    }
+
+    @Override
+    protected ZoneRules provideRules(String zoneId, boolean forCaching) {
+        // Ignore forCaching, as this is a static provider.
+        return cache.get(zoneId);
+    }
+
+    @Override
+    protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
+        return new TreeMap<>(
+                Collections.singletonMap(TimeZone.getTZDataVersion(),
+                        provideRules(zoneId, /* forCaching */ false)));
+    }
+
+    /*
+     * This implementation is only tested with OlsonTimeZone objects and depends on
+     * implementation details of that class:
+     *
+     * 0. TimeZone.getFrozenTimeZone() always returns an OlsonTimeZone object.
+     * 1. The first rule is always an InitialTimeZoneRule (guaranteed by spec).
+     * 2. AnnualTimeZoneRules are only used as "final rules".
+     * 3. The final rules are either 0 or 2 AnnualTimeZoneRules
+     * 4. The final rules have endYear set to MAX_YEAR.
+     * 5. Each transition generated by the rules changes either the raw offset, the total offset
+     *    or both.
+     * 6. There is a non-immense number of transitions for any rule before the final rules apply
+     *    (enforced via the arbitrary limit defined in MAX_TRANSITIONS).
+     *
+     * Assumptions #5 and #6 are not strictly required for this code to work, but hold for the
+     * the data and code at the time of implementation. If they were broken they would indicate
+     * an incomplete understanding of how ICU TimeZoneRules are used which would probably mean that
+     * this code needs to be updated.
+     *
+     * These assumptions are verified using the verify() method where appropriate.
+     */
+    protected static ZoneRules generateZoneRules(String zoneId) {
+        TimeZone timeZone = TimeZone.getFrozenTimeZone(zoneId);
+        // Assumption #0
+        verify(timeZone instanceof OlsonTimeZone, zoneId,
+                "Unexpected time zone class " + timeZone.getClass());
+        OlsonTimeZone tz = (OlsonTimeZone) timeZone;
+        TimeZoneRule[] rules = tz.getTimeZoneRules();
+        // Assumption #1
+        InitialTimeZoneRule initial = (InitialTimeZoneRule) rules[0];
+
+        ZoneOffset baseStandardOffset = millisToOffset(initial.getRawOffset());
+        ZoneOffset baseWallOffset =
+                millisToOffset((initial.getRawOffset() + initial.getDSTSavings()));
+
+        List<ZoneOffsetTransition> standardOffsetTransitionList = new ArrayList<>();
+        List<ZoneOffsetTransition> transitionList = new ArrayList<>();
+        List<ZoneOffsetTransitionRule> lastRules = new ArrayList<>();
+
+        int preLastDstSavings = 0;
+        AnnualTimeZoneRule last1 = null;
+        AnnualTimeZoneRule last2 = null;
+
+        TimeZoneTransition transition = tz.getNextTransition(Long.MIN_VALUE, false);
+        int transitionCount = 1;
+        // This loop has two possible exit conditions (in normal operation):
+        // 1. for zones that end with a static value and have no ongoing DST changes, it will exit
+        //    via the normal condition (transition != null)
+        // 2. for zones with ongoing DST changes (represented by a "final zone" in ICU4J, and by
+        //    "last rules" in java.time) the "break transitionLoop" will be used to exit the loop.
+        transitionLoop:
+        while (transition != null) {
+            TimeZoneRule from = transition.getFrom();
+            TimeZoneRule to = transition.getTo();
+            boolean hadEffect = false;
+            if (from.getRawOffset() != to.getRawOffset()) {
+                standardOffsetTransitionList.add(new ZoneOffsetTransition(
+                        TimeUnit.MILLISECONDS.toSeconds(transition.getTime()),
+                        millisToOffset(from.getRawOffset()),
+                        millisToOffset(to.getRawOffset())));
+                hadEffect = true;
+            }
+            int fromTotalOffset = from.getRawOffset() + from.getDSTSavings();
+            int toTotalOffset = to.getRawOffset() + to.getDSTSavings();
+            if (fromTotalOffset != toTotalOffset) {
+                transitionList.add(new ZoneOffsetTransition(
+                        TimeUnit.MILLISECONDS.toSeconds(transition.getTime()),
+                        millisToOffset(fromTotalOffset),
+                        millisToOffset(toTotalOffset)));
+                hadEffect = true;
+            }
+            // Assumption #5
+            verify(hadEffect, zoneId, "Transition changed neither total nor raw offset.");
+            if (to instanceof AnnualTimeZoneRule) {
+                // The presence of an AnnualTimeZoneRule is taken as an indication of a final rule.
+                if (last1 == null) {
+                    preLastDstSavings = from.getDSTSavings();
+                    last1 = (AnnualTimeZoneRule) to;
+                    // Assumption #4
+                    verify(last1.getEndYear() == AnnualTimeZoneRule.MAX_YEAR, zoneId,
+                            "AnnualTimeZoneRule is not permanent.");
+                } else {
+                    last2 = (AnnualTimeZoneRule) to;
+                    // Assumption #4
+                    verify(last2.getEndYear() == AnnualTimeZoneRule.MAX_YEAR, zoneId,
+                            "AnnualTimeZoneRule is not permanent.");
+
+                    // Assumption #3
+                    transition = tz.getNextTransition(transition.getTime(), false);
+                    verify(transition.getTo() == last1, zoneId,
+                            "Unexpected rule after 2 AnnualTimeZoneRules.");
+                    break transitionLoop;
+                }
+            } else {
+                // Assumption #2
+                verify(last1 == null, zoneId, "Unexpected rule after AnnualTimeZoneRule.");
+            }
+            verify(transitionCount <= MAX_TRANSITIONS, zoneId,
+                    "More than " + MAX_TRANSITIONS + " transitions.");
+            transition = tz.getNextTransition(transition.getTime(), false);
+            transitionCount++;
+        }
+        if (last1 != null) {
+            // Assumption #3
+            verify(last2 != null, zoneId, "Only one AnnualTimeZoneRule.");
+            lastRules.add(toZoneOffsetTransitionRule(last1, preLastDstSavings));
+            lastRules.add(toZoneOffsetTransitionRule(last2, last1.getDSTSavings()));
+        }
+
+        return ZoneRules.of(baseStandardOffset, baseWallOffset, standardOffsetTransitionList,
+                transitionList, lastRules);
+    }
+
+    /**
+     * Verify an assumption about the zone rules.
+     *
+     * @param check
+     *         {@code true} if the assumption holds, {@code false} otherwise.
+     * @param zoneId
+     *         Zone ID for which to check.
+     * @param message
+     *         Error description of a failed check.
+     * @throws ZoneRulesException
+     *         If and only if {@code check} is {@code false}.
+     */
+    private static void verify(boolean check, String zoneId, String message) {
+        if (!check) {
+            throw new ZoneRulesException(
+                    String.format("Failed verification of zone %s: %s", zoneId, message));
+        }
+    }
+
+    /**
+     * Transform an {@link AnnualTimeZoneRule} into an equivalent {@link ZoneOffsetTransitionRule}.
+     * This is only used for the "final rules".
+     *
+     * @param rule
+     *         The rule to transform.
+     * @param dstSavingMillisBefore
+     *         The DST offset before the first transition in milliseconds.
+     */
+    private static ZoneOffsetTransitionRule toZoneOffsetTransitionRule(
+            AnnualTimeZoneRule rule, int dstSavingMillisBefore) {
+        DateTimeRule dateTimeRule = rule.getRule();
+        // Calendar.JANUARY is 0, transform it into a proper Month.
+        Month month = Month.JANUARY.plus(dateTimeRule.getRuleMonth());
+        int dayOfMonthIndicator;
+        // Calendar.SUNDAY is 1, transform it into a proper DayOfWeek.
+        DayOfWeek dayOfWeek = DayOfWeek.SATURDAY.plus(dateTimeRule.getRuleDayOfWeek());
+        switch (dateTimeRule.getDateRuleType()) {
+            case DateTimeRule.DOM:
+                // Transition always on a specific day of the month.
+                dayOfMonthIndicator = dateTimeRule.getRuleDayOfMonth();
+                dayOfWeek = null;
+                break;
+            case DateTimeRule.DOW_GEQ_DOM:
+                // ICU representation matches java.time representation.
+                dayOfMonthIndicator = dateTimeRule.getRuleDayOfMonth();
+                break;
+            case DateTimeRule.DOW_LEQ_DOM:
+                // java.time uses a negative dayOfMonthIndicator to represent "Sun<=X" or "lastSun"
+                // rules. ICU uses this constant and the normal day. So "lastSun" in January would
+                // ruleDayOfMonth = 31 in ICU and dayOfMonthIndicator = -1 in java.time.
+                dayOfMonthIndicator = -month.maxLength() + dateTimeRule.getRuleDayOfMonth() - 1;
+                break;
+            case DateTimeRule.DOW:
+                // DOW is unspecified in the documentation and seems to never be used.
+                throw new ZoneRulesException("Date rule type DOW is unsupported");
+            default:
+                throw new ZoneRulesException(
+                        "Unexpected date rule type: " + dateTimeRule.getDateRuleType());
+        }
+        // Cast to int is save, as input is int.
+        int secondOfDay = (int) TimeUnit.MILLISECONDS.toSeconds(dateTimeRule.getRuleMillisInDay());
+        LocalTime time;
+        boolean timeEndOfDay;
+        if (secondOfDay == SECONDS_IN_DAY) {
+            time = LocalTime.MIDNIGHT;
+            timeEndOfDay = true;
+        } else {
+            time = LocalTime.ofSecondOfDay(secondOfDay);
+            timeEndOfDay = false;
+        }
+        ZoneOffsetTransitionRule.TimeDefinition timeDefinition;
+        switch (dateTimeRule.getTimeRuleType()) {
+            case DateTimeRule.WALL_TIME:
+                timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.WALL;
+                break;
+            case DateTimeRule.STANDARD_TIME:
+                timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.STANDARD;
+                break;
+            case DateTimeRule.UTC_TIME:
+                timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.UTC;
+                break;
+            default:
+                throw new ZoneRulesException(
+                        "Unexpected time rule type " + dateTimeRule.getTimeRuleType());
+        }
+        ZoneOffset standardOffset = millisToOffset(rule.getRawOffset());
+        ZoneOffset offsetBefore = millisToOffset(rule.getRawOffset() + dstSavingMillisBefore);
+        ZoneOffset offsetAfter = millisToOffset(
+                rule.getRawOffset() + rule.getDSTSavings());
+        return ZoneOffsetTransitionRule.of(
+                month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition,
+                standardOffset, offsetBefore, offsetAfter);
+    }
+
+    private static ZoneOffset millisToOffset(int offset) {
+        // Cast to int is save, as input is int.
+        return ZoneOffset.ofTotalSeconds((int) TimeUnit.MILLISECONDS.toSeconds(offset));
+    }
+
+    private static class ZoneRulesCache extends BasicLruCache<String, ZoneRules> {
+
+        ZoneRulesCache(int maxSize) {
+            super(maxSize);
+        }
+
+        @Override
+        protected ZoneRules create(String zoneId) {
+            String canonicalId = TimeZone.getCanonicalID(zoneId);
+            if (!canonicalId.equals(zoneId)) {
+                // Return the same object as the canonical one, to avoid wasting space, but cache
+                // it under the non-cannonical name as well, to avoid future getCanonicalID calls.
+                return get(canonicalId);
+            }
+            return generateZoneRules(zoneId);
+        }
+    }
+}
diff --git a/ojluni/src/main/java/java/time/zone/TzdbZoneRulesProvider.java b/ojluni/src/main/java/java/time/zone/TzdbZoneRulesProvider.java
deleted file mode 100644
index 6a9d012..0000000
--- a/ojluni/src/main/java/java/time/zone/TzdbZoneRulesProvider.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *  * Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- *
- *  * Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- *
- *  * Neither the name of JSR-310 nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package java.time.zone;
-
-import java.io.ByteArrayInputStream;
-import java.io.BufferedInputStream;
-import java.io.DataInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.StreamCorruptedException;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.NavigableMap;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Loads time-zone rules for 'TZDB'.
- *
- * @since 1.8
- */
-final class TzdbZoneRulesProvider extends ZoneRulesProvider {
-
-    /**
-     * All the regions that are available.
-     */
-    private List<String> regionIds;
-    /**
-     * Version Id of this tzdb rules
-     */
-    private String versionId;
-    /**
-     * Region to rules mapping
-     */
-    private final Map<String, Object> regionToRules = new ConcurrentHashMap<>();
-
-    /**
-     * Creates an instance.
-     * Created by the {@code ServiceLoader}.
-     *
-     * @throws ZoneRulesException if unable to load
-     */
-    public TzdbZoneRulesProvider() {
-        try {
-            String libDir = System.getProperty("java.home") + File.separator + "lib";
-            try (DataInputStream dis = new DataInputStream(
-                     new BufferedInputStream(new FileInputStream(
-                         new File(libDir, "tzdb.dat"))))) {
-                load(dis);
-            }
-        } catch (Exception ex) {
-            throw new ZoneRulesException("Unable to load TZDB time-zone rules", ex);
-        }
-    }
-
-    @Override
-    protected Set<String> provideZoneIds() {
-        return new HashSet<>(regionIds);
-    }
-
-    @Override
-    protected ZoneRules provideRules(String zoneId, boolean forCaching) {
-        // forCaching flag is ignored because this is not a dynamic provider
-        Object obj = regionToRules.get(zoneId);
-        if (obj == null) {
-            throw new ZoneRulesException("Unknown time-zone ID: " + zoneId);
-        }
-        try {
-            if (obj instanceof byte[]) {
-                byte[] bytes = (byte[]) obj;
-                DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes));
-                obj = Ser.read(dis);
-                regionToRules.put(zoneId, obj);
-            }
-            return (ZoneRules) obj;
-        } catch (Exception ex) {
-            throw new ZoneRulesException("Invalid binary time-zone data: TZDB:" + zoneId + ", version: " + versionId, ex);
-        }
-    }
-
-    @Override
-    protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
-        TreeMap<String, ZoneRules> map = new TreeMap<>();
-        ZoneRules rules = getRules(zoneId, false);
-        if (rules != null) {
-            map.put(versionId, rules);
-        }
-        return map;
-    }
-
-    /**
-     * Loads the rules from a DateInputStream, often in a jar file.
-     *
-     * @param dis  the DateInputStream to load, not null
-     * @throws Exception if an error occurs
-     */
-    private void load(DataInputStream dis) throws Exception {
-        if (dis.readByte() != 1) {
-            throw new StreamCorruptedException("File format not recognised");
-        }
-        // group
-        String groupId = dis.readUTF();
-        if ("TZDB".equals(groupId) == false) {
-            throw new StreamCorruptedException("File format not recognised");
-        }
-        // versions
-        int versionCount = dis.readShort();
-        for (int i = 0; i < versionCount; i++) {
-            versionId = dis.readUTF();
-        }
-        // regions
-        int regionCount = dis.readShort();
-        String[] regionArray = new String[regionCount];
-        for (int i = 0; i < regionCount; i++) {
-            regionArray[i] = dis.readUTF();
-        }
-        regionIds = Arrays.asList(regionArray);
-        // rules
-        int ruleCount = dis.readShort();
-        Object[] ruleArray = new Object[ruleCount];
-        for (int i = 0; i < ruleCount; i++) {
-            byte[] bytes = new byte[dis.readShort()];
-            dis.readFully(bytes);
-            ruleArray[i] = bytes;
-        }
-        // link version-region-rules
-        for (int i = 0; i < versionCount; i++) {
-            int versionRegionCount = dis.readShort();
-            regionToRules.clear();
-            for (int j = 0; j < versionRegionCount; j++) {
-                String region = regionArray[dis.readShort()];
-                Object rule = ruleArray[dis.readShort() & 0xffff];
-                regionToRules.put(region, rule);
-            }
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "TZDB[" + versionId + "]";
-    }
-}
diff --git a/ojluni/src/main/java/java/time/zone/ZoneRules.java b/ojluni/src/main/java/java/time/zone/ZoneRules.java
index 4719098..924f351 100644
--- a/ojluni/src/main/java/java/time/zone/ZoneRules.java
+++ b/ojluni/src/main/java/java/time/zone/ZoneRules.java
@@ -82,6 +82,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+// Android changed: remove mention of ZoneRulesProvider.
 /**
  * The rules defining how the zone offset varies for a single time-zone.
  * <p>
@@ -90,7 +91,6 @@
  * {@link ZoneOffsetTransitionRule} is used for future transitions that are based
  * on the result of an algorithm.
  * <p>
- * The rules are loaded via {@link ZoneRulesProvider} using a {@link ZoneId}.
  * The same rules may be shared internally between multiple zone IDs.
  * <p>
  * Serializing an instance of {@code ZoneRules} will store the entire set of rules.
diff --git a/ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java b/ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java
index 9523664..9ef9f1a 100644
--- a/ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java
+++ b/ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java
@@ -138,53 +138,9 @@
     private static final ConcurrentMap<String, ZoneRulesProvider> ZONES = new ConcurrentHashMap<>(512, 0.75f, 2);
 
     static {
-        // if the property java.time.zone.DefaultZoneRulesProvider is
-        // set then its value is the class name of the default provider
-        final List<ZoneRulesProvider> loaded = new ArrayList<>();
-        AccessController.doPrivileged(new PrivilegedAction<Object>() {
-            public Object run() {
-                String prop = System.getProperty("java.time.zone.DefaultZoneRulesProvider");
-                if (prop != null) {
-                    try {
-                        Class<?> c = Class.forName(prop, true, ClassLoader.getSystemClassLoader());
-                        ZoneRulesProvider provider = ZoneRulesProvider.class.cast(c.newInstance());
-                        registerProvider(provider);
-                        loaded.add(provider);
-                    } catch (Exception x) {
-                        throw new Error(x);
-                    }
-                } else {
-                    registerProvider(new TzdbZoneRulesProvider());
-                }
-                return null;
-            }
-        });
-
-        ServiceLoader<ZoneRulesProvider> sl = ServiceLoader.load(ZoneRulesProvider.class, ClassLoader.getSystemClassLoader());
-        Iterator<ZoneRulesProvider> it = sl.iterator();
-        while (it.hasNext()) {
-            ZoneRulesProvider provider;
-            try {
-                provider = it.next();
-            } catch (ServiceConfigurationError ex) {
-                if (ex.getCause() instanceof SecurityException) {
-                    continue;  // ignore the security exception, try the next provider
-                }
-                throw ex;
-            }
-            boolean found = false;
-            for (ZoneRulesProvider p : loaded) {
-                if (p.getClass() == provider.getClass()) {
-                    found = true;
-                }
-            }
-            if (!found) {
-                registerProvider0(provider);
-                loaded.add(provider);
-            }
-        }
-        // CopyOnWriteList could be slow if lots of providers and each added individually
-        PROVIDERS.addAll(loaded);
+        // Android changed: use a single hard-coded provider.
+        ZoneRulesProvider provider = new IcuZoneRulesProvider();
+        registerProvider(provider);
     }
 
     //-------------------------------------------------------------------------
diff --git a/ojluni/src/test/artrun b/ojluni/src/test/artrun
index 3037adb..e9afd78 100755
--- a/ojluni/src/test/artrun
+++ b/ojluni/src/test/artrun
@@ -100,7 +100,6 @@
 apache-xml-hostdex.jar
 core-tests-hostdex.jar
 core-libart-hostdex.jar
-core-lambda-stubs-hostdex.jar
 conscrypt-hostdex.jar
 core-ojtests-hostdex.jar  # This is the *one* addition that makes our OJ tests actually run. The rest of these are standard jars on the bootclasspath.
 core-oj-hostdex.jar
@@ -137,5 +136,3 @@
     $DEBUG_OPTION \
     "$@"
 
-
-temp_dir="$(mktemp -q -d -t "$(basename "$0").XXXXXX")"
diff --git a/ojluni/src/test/artrun-testng b/ojluni/src/test/artrun-testng
index f5aa95d..f6a7b71 100755
--- a/ojluni/src/test/artrun-testng
+++ b/ojluni/src/test/artrun-testng
@@ -16,4 +16,6 @@
 
 DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 
-$DIR/artrun -Xmx512m org.testng.TestNG -verbose 3 "$DIR/testng.xml"
+TESTNG_FILE=${1-testng.xml}
+
+$DIR/artrun -Xmx512m org.testng.TestNG -verbose 3 "$DIR/$TESTNG_FILE"
diff --git a/ojluni/src/test/testng-time.xml b/ojluni/src/test/testng-time.xml
new file mode 100644
index 0000000..c6cf3fd
--- /dev/null
+++ b/ojluni/src/test/testng-time.xml
@@ -0,0 +1,174 @@
+<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
+
+<suite name="OpenJDK8 test suite" verbose="1" allow-return-values="true" >
+  <test name="java.time test">
+    <classes>
+     <class name="tck.java.time.AbstractDateTimeTest" />
+     <class name="tck.java.time.AbstractTCKTest" />
+     <class name="tck.java.time.chrono.CopticChronology" />
+     <class name="tck.java.time.chrono.CopticDate" />
+     <class name="tck.java.time.chrono.CopticEra" />
+     <class name="tck.java.time.chrono.serial.TCKChronoLocalDateSerialization" />
+     <class name="tck.java.time.chrono.serial.TCKChronoLocalDateTimeSerialization" />
+     <class name="tck.java.time.chrono.serial.TCKChronologySerialization" />
+     <class name="tck.java.time.chrono.serial.TCKChronoZonedDateTimeSerialization" />
+     <class name="tck.java.time.chrono.serial.TCKCopticSerialization" />
+     <class name="tck.java.time.chrono.serial.TCKEraSerialization" />
+     <class name="tck.java.time.chrono.TCKChronoLocalDate" />
+     <class name="tck.java.time.chrono.TCKChronoLocalDateTime" />
+     <class name="tck.java.time.chrono.TCKChronology" />
+     <class name="tck.java.time.chrono.TCKChronoPeriod" />
+     <class name="tck.java.time.chrono.TCKChronoZonedDateTime" />
+     <class name="tck.java.time.chrono.TCKHijrahChronology" />
+     <class name="tck.java.time.chrono.TCKHijrahEra" />
+     <class name="tck.java.time.chrono.TCKIsoChronology" />
+     <class name="tck.java.time.chrono.TCKIsoEra" />
+     <class name="tck.java.time.chrono.TCKJapaneseChronology" />
+     <class name="tck.java.time.chrono.TCKJapaneseEra" />
+     <class name="tck.java.time.chrono.TCKMinguoChronology" />
+     <class name="tck.java.time.chrono.TCKMinguoEra" />
+     <class name="tck.java.time.chrono.TCKTestServiceLoader" />
+     <class name="tck.java.time.chrono.TCKThaiBuddhistChronology" />
+     <class name="tck.java.time.chrono.TCKThaiBuddhistEra" />
+     <class name="tck.java.time.format.TCKChronoPrinterParser" />
+     <class name="tck.java.time.format.TCKDateTimeFormatter" />
+     <class name="tck.java.time.format.TCKDateTimeFormatterBuilder" />
+     <class name="tck.java.time.format.TCKDateTimeFormatters" />
+     <class name="tck.java.time.format.TCKDateTimeParseResolver" />
+     <class name="tck.java.time.format.TCKDateTimeTextPrinting" />
+     <class name="tck.java.time.format.TCKFormatStyle" />
+     <class name="tck.java.time.format.TCKInstantPrinterParser" />
+     <class name="tck.java.time.format.TCKLocalizedFieldParser" />
+     <class name="tck.java.time.format.TCKLocalizedFieldPrinter" />
+     <class name="tck.java.time.format.TCKLocalizedPrinterParser" />
+     <class name="tck.java.time.format.TCKOffsetPrinterParser" />
+     <class name="tck.java.time.format.TCKPadPrinterParser" />
+     <class name="tck.java.time.format.TCKResolverStyle" />
+     <class name="tck.java.time.format.TCKSignStyle" />
+     <class name="tck.java.time.format.TCKTextStyle" />
+     <class name="tck.java.time.format.TCKZoneIdPrinterParser" />
+     <class name="tck.java.time.MockSimplePeriod" />
+     <class name="tck.java.time.serial.TCKClockSerialization" />
+     <class name="tck.java.time.serial.TCKDurationSerialization" />
+     <class name="tck.java.time.serial.TCKInstantSerialization" />
+     <class name="tck.java.time.serial.TCKLocalDateSerialization" />
+     <class name="tck.java.time.serial.TCKLocalDateTimeSerialization" />
+     <class name="tck.java.time.serial.TCKLocalTimeSerialization" />
+     <class name="tck.java.time.serial.TCKMonthDaySerialization" />
+     <class name="tck.java.time.serial.TCKOffsetDateTimeSerialization" />
+     <class name="tck.java.time.serial.TCKOffsetTimeSerialization" />
+     <class name="tck.java.time.serial.TCKPeriodSerialization" />
+     <class name="tck.java.time.serial.TCKYearMonthSerialization" />
+     <class name="tck.java.time.serial.TCKYearSerialization" />
+     <class name="tck.java.time.serial.TCKZonedDateTimeSerialization" />
+     <class name="tck.java.time.serial.TCKZoneIdSerialization" />
+     <class name="tck.java.time.serial.TCKZoneOffsetSerialization" />
+     <class name="tck.java.time.TCKClock" />
+     <class name="tck.java.time.TCKClock_Fixed" />
+     <class name="tck.java.time.TCKClock_Offset" />
+     <class name="tck.java.time.TCKClock_System" />
+     <class name="tck.java.time.TCKClock_Tick" />
+     <class name="tck.java.time.TCKDayOfWeek" />
+     <class name="tck.java.time.TCKDuration" />
+     <class name="tck.java.time.TCKInstant" />
+     <class name="tck.java.time.TCKLocalDate" />
+     <class name="tck.java.time.TCKLocalDateTime" />
+     <class name="tck.java.time.TCKLocalTime" />
+     <class name="tck.java.time.TCKMonth" />
+     <class name="tck.java.time.TCKMonthDay" />
+     <class name="tck.java.time.TCKOffsetDateTime" />
+     <class name="tck.java.time.TCKOffsetTime" />
+     <class name="tck.java.time.TCKPeriod" />
+     <class name="tck.java.time.TCKYear" />
+     <class name="tck.java.time.TCKYearMonth" />
+     <class name="tck.java.time.TCKZonedDateTime" />
+     <class name="tck.java.time.TCKZoneId" />
+     <class name="tck.java.time.TCKZoneOffset" />
+     <class name="tck.java.time.temporal.serial.TCKChronoFieldSerialization" />
+     <class name="tck.java.time.temporal.serial.TCKChronoUnitSerialization" />
+     <class name="tck.java.time.temporal.serial.TCKJulianFieldsSerialization" />
+     <class name="tck.java.time.temporal.serial.TCKValueRangeSerialization" />
+     <class name="tck.java.time.temporal.serial.TCKWeekFieldsSerialization" />
+     <class name="tck.java.time.temporal.TCKChronoField" />
+     <class name="tck.java.time.temporal.TCKChronoUnit" />
+     <class name="tck.java.time.temporal.TCKIsoFields" />
+     <class name="tck.java.time.temporal.TCKJulianFields" />
+     <class name="tck.java.time.temporal.TCKTemporalAdjusters" />
+     <class name="tck.java.time.temporal.TCKWeekFields" />
+     <class name="tck.java.time.TestIsoChronology" />
+     <class name="tck.java.time.zone.serial.TCKFixedZoneRulesSerialization" />
+     <class name="tck.java.time.zone.serial.TCKZoneOffsetTransitionRuleSerialization" />
+     <class name="tck.java.time.zone.serial.TCKZoneOffsetTransitionSerialization" />
+     <class name="tck.java.time.zone.serial.TCKZoneRulesSerialization" />
+     <class name="tck.java.time.zone.TCKFixedZoneRules" />
+     <class name="tck.java.time.zone.TCKZoneOffsetTransition" />
+     <class name="tck.java.time.zone.TCKZoneOffsetTransitionRule" />
+     <class name="tck.java.time.zone.TCKZoneRules" />
+     <class name="tck.java.time.zone.TCKZoneRulesProvider" />
+     <class name="test.java.time.AbstractTest" />
+     <class name="test.java.time.chrono.TestChronoLocalDate" />
+     <class name="test.java.time.chrono.TestChronologyPerf" />
+     <class name="test.java.time.chrono.TestIsoChronoImpl" />
+     <class name="test.java.time.chrono.TestJapaneseChronoImpl" />
+     <class name="test.java.time.chrono.TestJapaneseChronology" />
+     <class name="test.java.time.chrono.TestServiceLoader" />
+     <class name="test.java.time.chrono.TestThaiBuddhistChronoImpl" />
+     <class name="test.java.time.chrono.TestUmmAlQuraChronology" />
+     <class name="test.java.time.format.AbstractTestPrinterParser" />
+     <class name="test.java.time.format.MockIOExceptionAppendable" />
+     <class name="test.java.time.format.TestCharLiteralParser" />
+     <class name="test.java.time.format.TestCharLiteralPrinter" />
+     <class name="test.java.time.format.TestDateTimeFormatter" />
+     <class name="test.java.time.format.TestDateTimeFormatterBuilder" />
+     <class name="test.java.time.format.TestDateTimeParsing" />
+     <class name="test.java.time.format.TestDateTimeTextProvider" />
+     <class name="test.java.time.format.TestDecimalStyle" />
+     <class name="test.java.time.format.TestFractionPrinterParser" />
+     <class name="test.java.time.format.TestNonIsoFormatter" />
+     <class name="test.java.time.format.TestNumberParser" />
+     <class name="test.java.time.format.TestNumberPrinter" />
+     <class name="test.java.time.format.TestPadPrinterDecorator" />
+     <class name="test.java.time.format.TestReducedParser" />
+     <class name="test.java.time.format.TestReducedPrinter" />
+     <class name="test.java.time.format.TestSettingsParser" />
+     <class name="test.java.time.format.TestStringLiteralParser" />
+     <class name="test.java.time.format.TestStringLiteralPrinter" />
+     <class name="test.java.time.format.TestTextParser" />
+     <class name="test.java.time.format.TestTextPrinter" />
+     <class name="test.java.time.format.TestZoneOffsetParser" />
+     <class name="test.java.time.format.TestZoneOffsetPrinter" />
+     <class name="test.java.time.format.TestZoneTextPrinterParser" />
+     <class name="test.java.time.format.ZoneName" />
+     <class name="test.java.time.MockSimplePeriod" />
+     <class name="test.java.time.temporal.MockFieldNoValue" />
+     <class name="test.java.time.temporal.MockFieldValue" />
+     <class name="test.java.time.temporal.TestChronoField" />
+     <class name="test.java.time.temporal.TestChronoUnit" />
+     <class name="test.java.time.temporal.TestDateTimeBuilderCombinations" />
+     <class name="test.java.time.temporal.TestDateTimeValueRange" />
+     <class name="test.java.time.temporal.TestIsoWeekFields" />
+     <class name="test.java.time.temporal.TestJulianFields" />
+     <class name="test.java.time.TestClock_Fixed" />
+     <class name="test.java.time.TestClock_Offset" />
+     <class name="test.java.time.TestClock_System" />
+     <class name="test.java.time.TestClock_Tick" />
+     <class name="test.java.time.TestDuration" />
+     <class name="test.java.time.TestInstant" />
+     <class name="test.java.time.TestLocalDate" />
+     <class name="test.java.time.TestLocalDateTime" />
+     <class name="test.java.time.TestLocalTime" />
+     <class name="test.java.time.TestMonthDay" />
+     <class name="test.java.time.TestOffsetDateTime" />
+     <class name="test.java.time.TestOffsetDateTime_instants" />
+     <class name="test.java.time.TestOffsetTime" />
+     <class name="test.java.time.TestPeriod" />
+     <class name="test.java.time.TestYear" />
+     <class name="test.java.time.TestYearMonth" />
+     <class name="test.java.time.TestZonedDateTime" />
+     <class name="test.java.time.TestZoneId" />
+     <class name="test.java.time.TestZoneOffset" />
+     <class name="test.java.time.zone.TestFixedZoneRules" />
+    </classes>
+  </test>
+
+</suite>
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index 82a1c15..c38f3ed 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -812,11 +812,9 @@
     ojluni/src/main/java/java/time/zone/Ser.java \
     ojluni/src/main/java/java/time/zone/ZoneOffsetTransition.java \
     ojluni/src/main/java/java/time/zone/ZoneRulesException.java \
-    ojluni/src/main/java/java/time/zone/TzdbZoneRulesProvider.java \
     ojluni/src/main/java/java/time/zone/ZoneOffsetTransitionRule.java \
     ojluni/src/main/java/java/time/zone/ZoneRules.java \
     ojluni/src/main/java/java/time/zone/package-info.java \
-    ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java \
     ojluni/src/main/java/java/time/OffsetTime.java \
     ojluni/src/main/java/java/time/Year.java \
     ojluni/src/main/java/java/time/Clock.java \
@@ -1339,6 +1337,8 @@
     ojluni/src/main/java/com/sun/nio/file/ExtendedWatchEventModifier.java \
     ojluni/src/main/java/com/sun/nio/file/SensitivityWatchEventModifier.java \
     ojluni/src/main/java/java/beans/ChangeListenerMap.java \
+    ojluni/src/main/java/java/time/zone/IcuZoneRulesProvider.java \
+    ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java \
     ojluni/src/main/java/sun/misc/FDBigInteger.java \
     ojluni/src/main/java/sun/misc/FloatingDecimal.java \
     ojluni/src/main/java/java/lang/invoke/LambdaConversionException.java \