Home | History | Annotate | Download | only in localespi
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 /*
      4  *******************************************************************************
      5  * Copyright (C) 2008-2015, International Business Machines Corporation and    *
      6  * others. All Rights Reserved.                                                *
      7  *******************************************************************************
      8  */
      9 package com.ibm.icu.dev.test.localespi;
     10 
     11 import java.util.Collections;
     12 import java.util.HashSet;
     13 import java.util.Locale;
     14 import java.util.Set;
     15 import java.util.TimeZone;
     16 
     17 import org.junit.Test;
     18 
     19 import com.ibm.icu.dev.test.TestFmwk;
     20 import com.ibm.icu.text.TimeZoneNames;
     21 import com.ibm.icu.text.TimeZoneNames.NameType;
     22 import com.ibm.icu.util.ULocale;
     23 
     24 public class TimeZoneNameTest extends TestFmwk {
     25 
     26     private static final Set<String> ProblematicZones = new HashSet<String>();
     27     static {
     28         // Since tzdata2013e, Pacific/Johnston is defined as below:
     29         //
     30         //     Link Pacific/Honolulu Pacific/Johnston
     31         //
     32         // JDK TimeZone.getDisplayName no longer passes Pacific/Johnston to a
     33         // TimeZoneNameProvider implementation. As of CLDR 25M1, Pacific/Johnston
     34         // has a different set of names from Pacific/Honolulu. This test case
     35         // expects JRE calls a TimeZoneNameProvider without such normalization
     36         // (and I believe it's a JDK bug). For now, we ignore the test failure
     37         // caused by Pacific/Johnston with this the JDK problem.
     38         ProblematicZones.add("Pacific/Johnston");
     39     }
     40 
     41     @Test
     42     public void TestTimeZoneNames() {
     43         Locale[] locales = Locale.getAvailableLocales();
     44         String[] tzids = TimeZone.getAvailableIDs();
     45 
     46         for (Locale loc : locales) {
     47             boolean warningOnly = false;
     48             if (TestUtil.isExcluded(loc)) {
     49                 warningOnly = true;
     50             }
     51 
     52             for (String tzid : tzids) {
     53                 // Java has a problem when a provider does not supply all 4 names
     54                 // for a zone. For this reason, ICU TimeZoneName provider does not return
     55                 // localized names unless these 4 names are available.
     56 
     57                 String icuStdLong = getIcuDisplayName(tzid, false, TimeZone.LONG, loc);
     58                 String icuDstLong = getIcuDisplayName(tzid, true, TimeZone.LONG, loc);
     59                 String icuStdShort = getIcuDisplayName(tzid, false, TimeZone.SHORT, loc);
     60                 String icuDstShort = getIcuDisplayName(tzid, true, TimeZone.SHORT, loc);
     61 
     62                 if (icuStdLong != null && icuDstLong != null && icuStdShort != null && icuDstShort != null) {
     63                     checkDisplayNamePair(TimeZone.SHORT, tzid, loc, warningOnly || ProblematicZones.contains(tzid));
     64                     checkDisplayNamePair(TimeZone.LONG, tzid, loc, warningOnly || ProblematicZones.contains(tzid));
     65                 } else {
     66                     logln("Localized long standard name is not available for "
     67                             + tzid + " in locale " + loc + " in ICU");
     68                 }
     69             }
     70         }
     71     }
     72 
     73     private void checkDisplayNamePair(int style, String tzid, Locale loc, boolean warnOnly) {
     74         /* Note: There are two problems here.
     75          *
     76          * It looks Java 6 requires a TimeZoneNameProvider to return both standard name and daylight name
     77          * for a zone.  If the provider implementation only returns either of them, Java 6 also ignore
     78          * the other.  In ICU, there are zones which do not have daylight names, especially zones which
     79          * do not use daylight time.  This test case does not check a standard name if its daylight name
     80          * is not available because of the Java 6 implementation problem.
     81          *
     82          * Another problem is that ICU always use a standard name for a zone which does not use daylight
     83          * saving time even daylight name is requested.
     84          */
     85 
     86         String icuStdName = getIcuDisplayName(tzid, false, style, loc);
     87         String icuDstName = getIcuDisplayName(tzid, true, style, loc);
     88         if (icuStdName != null && icuDstName != null && !icuStdName.equals(icuDstName)) {
     89             checkDisplayName(false, style, tzid, loc, icuStdName, warnOnly);
     90             checkDisplayName(true, style, tzid, loc, icuDstName, warnOnly);
     91         }
     92     }
     93 
     94     private String getIcuDisplayName(String tzid, boolean daylight, int style, Locale loc) {
     95         String icuName = null;
     96         boolean[] isSystemID = new boolean[1];
     97         String canonicalID = com.ibm.icu.util.TimeZone.getCanonicalID(tzid, isSystemID);
     98         if (isSystemID[0]) {
     99             long date = System.currentTimeMillis();
    100             TimeZoneNames tznames = TimeZoneNames.getInstance(ULocale.forLocale(loc));
    101             switch (style) {
    102             case TimeZone.LONG:
    103                 icuName = daylight ?
    104                         tznames.getDisplayName(canonicalID, NameType.LONG_DAYLIGHT, date) :
    105                         tznames.getDisplayName(canonicalID, NameType.LONG_STANDARD, date);
    106                 break;
    107             case TimeZone.SHORT:
    108                 icuName = daylight ?
    109                         tznames.getDisplayName(canonicalID, NameType.SHORT_DAYLIGHT, date) :
    110                         tznames.getDisplayName(canonicalID, NameType.SHORT_STANDARD, date);
    111                 break;
    112             }
    113         }
    114         return icuName;
    115     }
    116 
    117     private void checkDisplayName(boolean daylight, int style,  String tzid, Locale loc, String icuname, boolean warnOnly) {
    118         String styleStr = (style == TimeZone.SHORT) ? "SHORT" : "LONG";
    119         TimeZone tz = TimeZone.getTimeZone(tzid);
    120         String name = tz.getDisplayName(daylight, style, loc);
    121 
    122         if (TestUtil.isICUExtendedLocale(loc)) {
    123             // The name should be taken from ICU
    124             if (!name.equals(icuname)) {
    125                 if (warnOnly) {
    126                     logln("WARNING: TimeZone name by ICU is " + icuname + ", but got " + name
    127                             + " for time zone " + tz.getID() + " in locale " + loc
    128                             + " (daylight=" + daylight + ", style=" + styleStr + ")");
    129 
    130                 } else {
    131                     errln("FAIL: TimeZone name by ICU is " + icuname + ", but got " + name
    132                             + " for time zone " + tz.getID() + " in locale " + loc
    133                             + " (daylight=" + daylight + ", style=" + styleStr + ")");
    134                 }
    135             }
    136         } else {
    137             if (!name.equals(icuname)) {
    138                 logln("INFO: TimeZone name by ICU is " + icuname + ", but got " + name
    139                         + " for time zone " + tz.getID() + " in locale " + loc
    140                         + " (daylight=" + daylight + ", style=" + styleStr + ")");
    141             }
    142             // Try explicit ICU locale (xx_yy_ICU)
    143             Locale icuLoc = TestUtil.toICUExtendedLocale(loc);
    144             name = tz.getDisplayName(daylight, style, icuLoc);
    145             if (!name.equals(icuname)) {
    146                 if (warnOnly) {
    147                     logln("WARNING: TimeZone name by ICU is " + icuname + ", but got " + name
    148                             + " for time zone " + tz.getID() + " in locale " + icuLoc
    149                             + " (daylight=" + daylight + ", style=" + styleStr + ")");
    150                 } else {
    151                     errln("FAIL: TimeZone name by ICU is " + icuname + ", but got " + name
    152                             + " for time zone " + tz.getID() + " in locale " + icuLoc
    153                             + " (daylight=" + daylight + ", style=" + styleStr + ")");
    154                 }
    155             }
    156         }
    157     }
    158 
    159     @Test
    160     public void testGetInstance_Locale() {
    161         TimeZoneNames uLocaleInstance = TimeZoneNames.getInstance(ULocale.CANADA);
    162         TimeZoneNames localeInstance = TimeZoneNames.getInstance(Locale.CANADA);
    163 
    164         Set<String> uLocaleAvailableIds = uLocaleInstance.getAvailableMetaZoneIDs();
    165         Set<String> localeAvailableIds = localeInstance.getAvailableMetaZoneIDs();
    166         assertEquals("Available ids", uLocaleAvailableIds, localeAvailableIds);
    167 
    168         for (String availableId : uLocaleAvailableIds) {
    169             long date = 1458385200000L;
    170             TimeZoneNames.NameType nameType = TimeZoneNames.NameType.SHORT_GENERIC;
    171             String uLocaleName = uLocaleInstance.getDisplayName(availableId, nameType, date);
    172             String localeName = localeInstance.getDisplayName(availableId, nameType, date);
    173             assertEquals("Id: " + availableId, uLocaleName, localeName);
    174         }
    175     }
    176 
    177     @Test
    178     public void testGetAvailableMetaZoneIDs() {
    179         TimeZoneNames japaneseNames = TimeZoneNames.getInstance(ULocale.JAPANESE);
    180         Set<String> allJapan = japaneseNames.getAvailableMetaZoneIDs();
    181 
    182         TimeZoneNames tzdbNames = TimeZoneNames.getTZDBInstance(ULocale.CHINESE);
    183         Set<String> tzdbAll = tzdbNames.getAvailableMetaZoneIDs();
    184 
    185         // The data is the same in the current implementation.
    186         assertEquals("MetaZone IDs different between locales", allJapan, tzdbAll);
    187 
    188         // Make sure that there is something.
    189         assertTrue("count of zone ids is less than 100", allJapan.size() >= 180);
    190     }
    191 
    192     @Test
    193     public void testGetAvailableMetaZoneIDs_String() {
    194         TimeZoneNames japaneseNames = TimeZoneNames.getInstance(ULocale.JAPANESE);
    195         assertEquals("Timezone name mismatch", Collections.singleton("America_Pacific"),
    196                 japaneseNames.getAvailableMetaZoneIDs("America/Los_Angeles"));
    197 
    198         TimeZoneNames tzdbNames = TimeZoneNames.getTZDBInstance(ULocale.CHINESE);
    199         assertEquals("Timezone name mismatch", Collections.singleton("Taipei"),
    200                 tzdbNames.getAvailableMetaZoneIDs("Asia/Taipei"));
    201     }
    202 
    203     @Test
    204     public void testGetMetaZoneDisplayName() {
    205         TimeZoneNames usNames = TimeZoneNames.getInstance(ULocale.US);
    206 
    207         String europeanCentralName = usNames.getMetaZoneDisplayName("Europe_Central",
    208                 TimeZoneNames.NameType.LONG_STANDARD);
    209         assertEquals("Timezone name mismatch", "Central European Standard Time",
    210                 europeanCentralName);
    211 
    212         TimeZoneNames tzdbNames = TimeZoneNames.getTZDBInstance(ULocale.CHINESE);
    213         String americaPacificName = tzdbNames.getMetaZoneDisplayName("America_Pacific",
    214                 TimeZoneNames.NameType.SHORT_DAYLIGHT);
    215         assertEquals("Timezone name mismatch", "PDT", americaPacificName);
    216     }
    217 
    218     @Test
    219     public void testGetMetaZoneID() {
    220         TimeZoneNames usNames = TimeZoneNames.getInstance(ULocale.US);
    221 
    222         String europeanCentralName = usNames.getMetaZoneID("Europe/Paris", 0);
    223         assertEquals("Timezone name mismatch", "Europe_Central", europeanCentralName);
    224 
    225         TimeZoneNames tzdbNames = TimeZoneNames.getTZDBInstance(ULocale.KOREAN);
    226         String seoulName = tzdbNames.getMetaZoneID("Asia/Seoul", 0);
    227         assertEquals("Timezone name mismatch", "Korea", seoulName);
    228 
    229         // Now try Jan 1st 1945 GMT
    230         seoulName = tzdbNames.getMetaZoneID("Asia/Seoul", -786240000000L);
    231         assertNull("Timezone name mismatch", seoulName);
    232     }
    233 
    234     @Test
    235     public void testGetTimeZoneDisplayName() {
    236         TimeZoneNames frenchNames = TimeZoneNames.getInstance(ULocale.FRENCH);
    237         String dublinName = frenchNames.getTimeZoneDisplayName("Europe/Dublin",
    238                 TimeZoneNames.NameType.LONG_DAYLIGHT);
    239         assertEquals("Timezone name mismatch", "heure dt irlandaise", dublinName);
    240 
    241         String dublinLocation = frenchNames.getTimeZoneDisplayName("Europe/Dublin",
    242                 TimeZoneNames.NameType.EXEMPLAR_LOCATION);
    243         assertEquals("Timezone name mismatch", "Dublin", dublinLocation);
    244 
    245         // All the names returned by this are null.
    246         TimeZoneNames tzdbNames = TimeZoneNames.getTZDBInstance(ULocale.KOREAN);
    247         for (String tzId : TimeZone.getAvailableIDs()) {
    248             for (TimeZoneNames.NameType nameType : TimeZoneNames.NameType.values()) {
    249                 String name = tzdbNames.getTimeZoneDisplayName(tzId, nameType);
    250                 assertNull("TZ:" + tzId + ", NameType: " + nameType + ", value: " + name, name);
    251             }
    252         }
    253     }
    254 }
    255