diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2021-05-05 01:02:59 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2021-05-05 01:02:59 +0000 |
commit | dc9fae15fa1c7be516be53bf22ade88c35b9dba2 (patch) | |
tree | 954027df47ab2e10526321a6d60b46726dd50af5 | |
parent | 717915f521b71b069798d66dba8a38faabbe05a8 (diff) | |
parent | 73a047e99c5cdda1d12d2301a3f28870dc5a45c5 (diff) | |
download | icu-dc9fae15fa1c7be516be53bf22ade88c35b9dba2.tar.gz |
Snap for 7336869 from 73a047e99c5cdda1d12d2301a3f28870dc5a45c5 to sc-d1-release
Change-Id: I739ad5b78456e1342299cb56410a2420f9378743
5 files changed, 161 insertions, 14 deletions
diff --git a/android_icu4j/api/intra/current.txt b/android_icu4j/api/intra/current.txt index d3cc4cc87..317a84368 100644 --- a/android_icu4j/api/intra/current.txt +++ b/android_icu4j/api/intra/current.txt @@ -74,6 +74,13 @@ package com.android.icu.text { method @NonNull public static com.android.icu.text.ExtendedTimeZoneNames getInstance(@NonNull android.icu.util.ULocale); method @NonNull public android.icu.text.TimeZoneNames getTimeZoneNames(); method @Nullable public com.android.icu.text.ExtendedTimeZoneNames.MatchedTimeZone matchName(@NonNull CharSequence, int, @NonNull String); + method @Nullable public com.android.icu.text.ExtendedTimeZoneNames.Match matchNameToBeRenamed(@NonNull CharSequence, int, @NonNull String); + } + + public static final class ExtendedTimeZoneNames.Match { + method public int getMatchLength(); + method @NonNull public String getTzId(); + method public boolean isDst(); } public static class ExtendedTimeZoneNames.MatchedTimeZone { diff --git a/android_icu4j/api/legacy_platform/current.txt b/android_icu4j/api/legacy_platform/current.txt index a81a0c650..692b2b1bf 100644 --- a/android_icu4j/api/legacy_platform/current.txt +++ b/android_icu4j/api/legacy_platform/current.txt @@ -81,6 +81,7 @@ package com.android.i18n.timezone { } public final class CountryZonesFinder { + method @Nullable public String findCanonicalTimeZoneId(String); method public java.util.List<java.lang.String> lookupAllCountryIsoCodes(); method public com.android.i18n.timezone.CountryTimeZones lookupCountryTimeZones(String); method public java.util.List<com.android.i18n.timezone.CountryTimeZones> lookupCountryTimeZonesForZoneId(String); diff --git a/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/CountryZonesFinder.java b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/CountryZonesFinder.java index 80a316e1f..61d9a1895 100644 --- a/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/CountryZonesFinder.java +++ b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/CountryZonesFinder.java @@ -19,6 +19,7 @@ package com.android.i18n.timezone; import static com.android.i18n.timezone.XmlUtils.normalizeCountryIso; import com.android.i18n.timezone.CountryTimeZones.TimeZoneMapping; +import libcore.util.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -57,10 +58,11 @@ public final class CountryZonesFinder { /** * Returns an immutable list of {@link CountryTimeZones} for countries that use the specified - * time zone. An exact, case-sensitive match is performed on the zone ID. If the match but the method also - * checks for alternative zone IDs. This method never returns null and will usually return a - * list containing a single element. It can return an empty list if the zone ID is - * not recognized or it is not associated with a country. + * time zone. An exact, case-sensitive match is performed on the zone ID. Search is done + * over currently used time zone IDs and also over no longer used deprecated(alternative) IDs. + * This method never returns null and will usually return a list containing a single element. + * It can return an empty list if the zone ID is not recognized or it is not associated with a + * country. */ @libcore.api.CorePlatformApi public List<CountryTimeZones> lookupCountryTimeZonesForZoneId(String zoneId) { @@ -104,4 +106,37 @@ public final class CountryZonesFinder { } return null; } + + /** + * Returns a canonical time zone ID for the {@code timeZoneId} specified. It is intended for use + * when behavioral equivalence of time zones needs to be determined. + * + * <p>When a time zone ID is returned, it is guaranteed to have the same offset / daylight + * savings behavior as the argument, but it might be used in a different country and could + * have different I18N properties like display name. The original {@code timeZoneId} will + * often be returned. + * + * <p>If {@code timeZoneId} is unknown or not associated with a country, {@code null} is + * returned. e.g. time zones such as Etc/GMT+-XX. + * + * This method behavior is based on tzlookup.xml file and works with Olson IDs attached to + * countries, unlike {@link android.icu.util.TimeZone} which works with wider set of arguments. + */ + @libcore.api.CorePlatformApi + @Nullable + public String findCanonicalTimeZoneId(String timeZoneId) { + for (CountryTimeZones countryTimeZones : countryTimeZonesList) { + + // notafter is ignored as timeZoneId might be deprecated a while ago + List<TimeZoneMapping> countryTimeZoneMappings = countryTimeZones.getTimeZoneMappings(); + for (TimeZoneMapping timeZoneMapping : countryTimeZoneMappings) { + if (timeZoneMapping.getTimeZoneId().equals(timeZoneId) + || timeZoneMapping.getAlternativeIds().contains(timeZoneId)) { + return timeZoneMapping.getTimeZoneId(); + } + } + } + + return null; + } } diff --git a/android_icu4j/libcore_bridge/src/java/com/android/icu/text/ExtendedTimeZoneNames.java b/android_icu4j/libcore_bridge/src/java/com/android/icu/text/ExtendedTimeZoneNames.java index 57c7367bc..37c60635f 100644 --- a/android_icu4j/libcore_bridge/src/java/com/android/icu/text/ExtendedTimeZoneNames.java +++ b/android_icu4j/libcore_bridge/src/java/com/android/icu/text/ExtendedTimeZoneNames.java @@ -54,7 +54,55 @@ public class ExtendedTimeZoneNames { private final ULocale locale; private final TimeZoneNames timeZoneNames; +/** + * A class representing the return result of {@link #matchName(CharSequence, int, String)} + * + * @hide + */ + @IntraCoreApi + public static final class Match { + + private final int matchLength; + private final @NonNull String tzId; + private final boolean isDst; + private Match(int matchLength, @NonNull String tzId, boolean isDst) { + this.matchLength = matchLength; + this.tzId = tzId; + this.isDst = isDst; + } + + /** + * Returns the number of chars in the matched name. + * + * @hide + */ + @IntraCoreApi + public int getMatchLength() { + return matchLength; + } + + /** + * Returns the time zone id associated with the matched name. + * + * @hide + */ + @IntraCoreApi + public @NonNull String getTzId() { + return tzId; + } + + /** + * Returns true if the matched name is a display name for daylight saving time. For example, + * returns true for "Pacific Daylight Time", but false for "Pacific Standard Time". + * + * @hide + */ + @IntraCoreApi + public boolean isDst() { + return isDst; + } + } /** * A class representing the return result of {@link #matchName(CharSequence, int, String)} * @@ -131,6 +179,38 @@ public class ExtendedTimeZoneNames { } /** + * Returns {@link Match} if a time zone name in ICU can be matched against the input + * CharSequence {@code s}. + * The best match is found by the following principles: + * <ul> + * <li>Length of the matched name. Longest name matched to the given {@code s} has the + * highest priority.</li> + * <li>The current time zone and meta zones possible in the current country have higher + * priority than other zones.</li> + * <li>If only meta zones are matched, the country/region in the locale is used to select + * a reference time zone. For example, if the name is "Pacific Standard Time" and the country + * is US, America/Los_Angeles is returned.</li> + * </ul> + * + * @param text input string to be matched against time zone names in ICU + * @param start the begin index in the CharSequence {@code s} + * @param currentTzId the time zone ID prioritized to be matched if multiple time zone IDs can + * be matched and this is one of the matched IDs. + * @return null if no match is found + * + * @hide + */ + @IntraCoreApi + public @Nullable Match matchNameToBeRenamed(@NonNull CharSequence text, int start, + @NonNull String currentTzId) { + MatchedTimeZone matchedTimeZone = matchName(text, start, currentTzId); + if (matchedTimeZone == null) { + return null; + } + return new Match(matchedTimeZone.matchLength, matchedTimeZone.tzId, matchedTimeZone.isDst); + } + + /** * Returns {@link MatchedTimeZone} if a time zone name in ICU can be matched against the input * CharSequence {@code s}. * The best match is found by the following principles: diff --git a/android_icu4j/testing/src/com/android/i18n/test/timezone/CountryZonesFinderTest.java b/android_icu4j/testing/src/com/android/i18n/test/timezone/CountryZonesFinderTest.java index 64ec0fd0d..549c8899f 100644 --- a/android_icu4j/testing/src/com/android/i18n/test/timezone/CountryZonesFinderTest.java +++ b/android_icu4j/testing/src/com/android/i18n/test/timezone/CountryZonesFinderTest.java @@ -16,22 +16,26 @@ package com.android.i18n.test.timezone; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.icu.testsharding.MainTestShard; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; import com.android.i18n.timezone.CountryTimeZones; import com.android.i18n.timezone.CountryTimeZones.TimeZoneMapping; import com.android.i18n.timezone.CountryZonesFinder; -import android.icu.testsharding.MainTestShard; +import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.fail; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; @MainTestShard public class CountryZonesFinderTest { @@ -119,6 +123,26 @@ public class CountryZonesFinderTest { assertNull(countryZonesFinder.lookupCountryTimeZones("DOES_NOT_EXIST")); } + @Test + public void findCanonicalTimeZoneId() { + TimeZoneMapping usesNewZoneId = timeZoneMappingWithAlts("America/Detroit", + list("US/Michigan")); + TimeZoneMapping usesOldZoneId = timeZoneMappingWithAlts("US/Central", + list("America/Chicago")); + CountryTimeZones countryWithAlternativeZones = CountryTimeZones.createValidated( + "us", "America/Detroit" /* defaultTimeZoneId */, false /* defaultTimeZoneBoost */, + false /* everUsesUtc */, + list(usesNewZoneId, usesOldZoneId), + "debug info"); + CountryZonesFinder countryZonesFinder = + CountryZonesFinder.createForTests(list(countryWithAlternativeZones)); + + assertEquals(countryZonesFinder.findCanonicalTimeZoneId("America/Chicago"), "US/Central"); + assertEquals(countryZonesFinder.findCanonicalTimeZoneId("US/Michigan"), "America/Detroit"); + assertEquals(countryZonesFinder.findCanonicalTimeZoneId("America/Detroit"), "America/Detroit"); + assertNull(countryZonesFinder.findCanonicalTimeZoneId("Mars/Base")); + } + private static <X> void assertEqualsAndImmutable(List<X> expected, List<X> actual) { assertEquals(expected, actual); assertImmutableList(actual); |