1 /*********************************************************************** 
   3  * Copyright (c) 1997-2015, International Business Machines Corporation 
   4  * and others. All Rights Reserved. 
   5  ***********************************************************************/ 
   7 #include "unicode/utypes.h" 
   9 #if !UCONFIG_NO_FORMATTING 
  11 #include "unicode/timezone.h" 
  12 #include "unicode/simpletz.h" 
  13 #include "unicode/calendar.h" 
  14 #include "unicode/gregocal.h" 
  15 #include "unicode/resbund.h" 
  16 #include "unicode/strenum.h" 
  17 #include "unicode/uversion.h" 
  24 #define CASE(id,test) case id:                               \ 
  27                               logln(#test "---"); logln(""); \ 
  32 // ***************************************************************************** 
  34 // ***************************************************************************** 
  36 // Some test case data is current date/tzdata version sensitive and producing errors 
  37 // when year/rule are changed. Although we want to keep our eyes on test failures 
  38 // caused by tzdata changes while development, keep maintaining test data in maintenance 
  39 // stream is a little bit hassle. ICU 49 or later versions are using minor version field 
  40 // to indicate a development build (0) or official release build (others). For development 
  41 // builds, a test failure triggers an error, while release builds only report them in 
  42 // verbose mode with logln. 
  43 static UBool isDevelopmentBuild 
= (U_ICU_VERSION_MINOR_NUM 
== 0); 
  45 void TimeZoneTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/ ) 
  48         logln("TestSuite TestTimeZone"); 
  51     TESTCASE_AUTO(TestPRTOffset
); 
  52     TESTCASE_AUTO(TestVariousAPI518
); 
  53     TESTCASE_AUTO(TestGetAvailableIDs913
); 
  54     TESTCASE_AUTO(TestGenericAPI
); 
  55     TESTCASE_AUTO(TestRuleAPI
); 
  56     TESTCASE_AUTO(TestShortZoneIDs
); 
  57     TESTCASE_AUTO(TestCustomParse
); 
  58     TESTCASE_AUTO(TestDisplayName
); 
  59     TESTCASE_AUTO(TestDSTSavings
); 
  60     TESTCASE_AUTO(TestAlternateRules
); 
  61     TESTCASE_AUTO(TestCountries
);  
  62     TESTCASE_AUTO(TestHistorical
); 
  63     TESTCASE_AUTO(TestEquivalentIDs
); 
  64     TESTCASE_AUTO(TestAliasedNames
); 
  65     TESTCASE_AUTO(TestFractionalDST
); 
  66     TESTCASE_AUTO(TestFebruary
); 
  67     TESTCASE_AUTO(TestCanonicalIDAPI
); 
  68     TESTCASE_AUTO(TestCanonicalID
); 
  69     TESTCASE_AUTO(TestDisplayNamesMeta
); 
  70     TESTCASE_AUTO(TestGetRegion
); 
  71     TESTCASE_AUTO(TestGetAvailableIDsNew
); 
  72     TESTCASE_AUTO(TestGetUnknown
); 
  73     TESTCASE_AUTO(TestGetWindowsID
); 
  74     TESTCASE_AUTO(TestGetIDForWindowsID
); 
  78 const int32_t TimeZoneTest::millisPerHour 
= 3600000; 
  80 // --------------------------------------------------------------------------------- 
  83  * Generic API testing for API coverage. 
  86 TimeZoneTest::TestGenericAPI() 
  88     UnicodeString 
id("NewGMT"); 
  89     int32_t offset 
= 12345; 
  91     SimpleTimeZone 
*zone 
= new SimpleTimeZone(offset
, id
); 
  92     if (zone
->useDaylightTime()) errln("FAIL: useDaylightTime should return FALSE"); 
  94     TimeZone
* zoneclone 
= zone
->clone(); 
  95     if (!(*zoneclone 
== *zone
)) errln("FAIL: clone or operator== failed"); 
  96     zoneclone
->setID("abc"); 
  97     if (!(*zoneclone 
!= *zone
)) errln("FAIL: clone or operator!= failed"); 
 100     zoneclone 
= zone
->clone(); 
 101     if (!(*zoneclone 
== *zone
)) errln("FAIL: clone or operator== failed"); 
 102     zoneclone
->setRawOffset(45678); 
 103     if (!(*zoneclone 
!= *zone
)) errln("FAIL: clone or operator!= failed"); 
 105     SimpleTimeZone 
copy(*zone
); 
 106     if (!(copy 
== *zone
)) errln("FAIL: copy constructor or operator== failed"); 
 107     copy 
= *(SimpleTimeZone
*)zoneclone
; 
 108     if (!(copy 
== *zoneclone
)) errln("FAIL: assignment operator or operator== failed"); 
 110     TimeZone
* saveDefault 
= TimeZone::createDefault(); 
 111     logln((UnicodeString
)"TimeZone::createDefault() => " + saveDefault
->getID(id
)); 
 113     TimeZone::adoptDefault(zone
); 
 114     TimeZone
* defaultzone 
= TimeZone::createDefault(); 
 115     if (defaultzone 
== zone 
|| 
 116         !(*defaultzone 
== *zone
)) 
 117         errln("FAIL: createDefault failed"); 
 118     TimeZone::adoptDefault(saveDefault
); 
 122     logln("call uprv_timezone() which uses the host"); 
 123     logln("to get the difference in seconds between coordinated universal"); 
 124     logln("time and local time. E.g., -28,800 for PST (GMT-8hrs)"); 
 126     int32_t tzoffset 
= uprv_timezone(); 
 127     if ((tzoffset 
% 900) != 0) { 
 129          * Ticket#6364 and #7648 
 130          * A few time zones are using GMT offests not a multiple of 15 minutes. 
 131          * Therefore, we should not interpret such case as an error. 
 132          * We downgrade this from errln to infoln. When we see this message, 
 133          * we should examine if it is ignorable or not. 
 135         infoln("WARNING: t_timezone may be incorrect. It is not a multiple of 15min.", tzoffset
); 
 138     TimeZone
* hostZone 
= TimeZone::detectHostTimeZone(); 
 139     /* Host time zone's offset should match the offset returned by uprv_timezone() */ 
 140     if (hostZone
->getRawOffset() != tzoffset 
* (-1000)) { 
 141         errln("FAIL: detectHostTimeZone()'s raw offset != host timezone's offset"); 
 145     UErrorCode status 
= U_ZERO_ERROR
; 
 146     const char* tzver 
= TimeZone::getTZDataVersion(status
); 
 147     if (U_FAILURE(status
)) { 
 148         errcheckln(status
, "FAIL: getTZDataVersion failed - %s", u_errorName(status
)); 
 149     } else if (uprv_strlen(tzver
) != 5 /* 4 digits + 1 letter */) { 
 150         errln((UnicodeString
)"FAIL: getTZDataVersion returned " + tzver
); 
 152         logln((UnicodeString
)"tzdata version: " + tzver
); 
 156 // --------------------------------------------------------------------------------- 
 159  * Test the setStartRule/setEndRule API calls. 
 162 TimeZoneTest::TestRuleAPI() 
 164     UErrorCode status 
= U_ZERO_ERROR
; 
 166     UDate offset 
= 60*60*1000*1.75; // Pick a weird offset 
 167     SimpleTimeZone 
*zone 
= new SimpleTimeZone((int32_t)offset
, "TestZone"); 
 168     if (zone
->useDaylightTime()) errln("FAIL: useDaylightTime should return FALSE"); 
 170     // Establish our expected transition times.  Do this with a non-DST 
 171     // calendar with the (above) declared local offset. 
 172     GregorianCalendar 
*gc 
= new GregorianCalendar(*zone
, status
); 
 173     if (failure(status
, "new GregorianCalendar", TRUE
)) return; 
 175     gc
->set(1990, UCAL_MARCH
, 1); 
 176     UDate marchOneStd 
= gc
->getTime(status
); // Local Std time midnight 
 178     gc
->set(1990, UCAL_JULY
, 1); 
 179     UDate julyOneStd 
= gc
->getTime(status
); // Local Std time midnight 
 180     if (failure(status
, "GregorianCalendar::getTime")) return; 
 182     // Starting and ending hours, WALL TIME 
 183     int32_t startHour 
= (int32_t)(2.25 * 3600000); 
 184     int32_t endHour   
= (int32_t)(3.5  * 3600000); 
 186     zone
->setStartRule(UCAL_MARCH
, 1, 0, startHour
, status
); 
 187     zone
->setEndRule  (UCAL_JULY
,  1, 0, endHour
, status
); 
 190     gc 
= new GregorianCalendar(*zone
, status
); 
 191     if (failure(status
, "new GregorianCalendar")) return; 
 193     UDate marchOne 
= marchOneStd 
+ startHour
; 
 194     UDate julyOne 
= julyOneStd 
+ endHour 
- 3600000; // Adjust from wall to Std time 
 196     UDate expMarchOne 
= 636251400000.0; 
 197     if (marchOne 
!= expMarchOne
) 
 199         errln((UnicodeString
)"FAIL: Expected start computed as " + marchOne 
+ 
 200           " = " + dateToString(marchOne
)); 
 201         logln((UnicodeString
)"      Should be                  " + expMarchOne 
+ 
 202           " = " + dateToString(expMarchOne
)); 
 205     UDate expJulyOne 
= 646793100000.0; 
 206     if (julyOne 
!= expJulyOne
) 
 208         errln((UnicodeString
)"FAIL: Expected start computed as " + julyOne 
+ 
 209           " = " + dateToString(julyOne
)); 
 210         logln((UnicodeString
)"      Should be                  " + expJulyOne 
+ 
 211           " = " + dateToString(expJulyOne
)); 
 214     testUsingBinarySearch(*zone
, date(90, UCAL_JANUARY
, 1), date(90, UCAL_JUNE
, 15), marchOne
); 
 215     testUsingBinarySearch(*zone
, date(90, UCAL_JUNE
, 1), date(90, UCAL_DECEMBER
, 31), julyOne
); 
 217     if (zone
->inDaylightTime(marchOne 
- 1000, status
) || 
 218         !zone
->inDaylightTime(marchOne
, status
)) 
 219         errln("FAIL: Start rule broken"); 
 220     if (!zone
->inDaylightTime(julyOne 
- 1000, status
) || 
 221         zone
->inDaylightTime(julyOne
, status
)) 
 222         errln("FAIL: End rule broken"); 
 224     zone
->setStartYear(1991); 
 225     if (zone
->inDaylightTime(marchOne
, status
) || 
 226         zone
->inDaylightTime(julyOne 
- 1000, status
)) 
 227         errln("FAIL: Start year broken"); 
 229     failure(status
, "TestRuleAPI"); 
 235 TimeZoneTest::findTransition(const TimeZone
& tz
, 
 236                              UDate min
, UDate max
) { 
 237     UErrorCode ec 
= U_ZERO_ERROR
; 
 239     UBool startsInDST 
= tz
.inDaylightTime(min
, ec
); 
 240     if (failure(ec
, "TimeZone::inDaylightTime")) return; 
 241     if (tz
.inDaylightTime(max
, ec
) == startsInDST
) { 
 242         logln("Error: " + tz
.getID(id
) + ".inDaylightTime(" + dateToString(min
) + ") = " + (startsInDST
?"TRUE":"FALSE") + 
 243               ", inDaylightTime(" + dateToString(max
) + ") = " + (startsInDST
?"TRUE":"FALSE")); 
 246     if (failure(ec
, "TimeZone::inDaylightTime")) return; 
 247     while ((max 
- min
) > INTERVAL
) { 
 248         UDate mid 
= (min 
+ max
) / 2; 
 249         if (tz
.inDaylightTime(mid
, ec
) == startsInDST
) { 
 254         if (failure(ec
, "TimeZone::inDaylightTime")) return; 
 256     min 
= 1000.0 * uprv_floor(min
/1000.0); 
 257     max 
= 1000.0 * uprv_floor(max
/1000.0); 
 258     logln(tz
.getID(id
) + " Before: " + min
/1000 + " = " + 
 259           dateToString(min
,s
,tz
)); 
 260     logln(tz
.getID(id
) + " After:  " + max
/1000 + " = " + 
 261           dateToString(max
,s
,tz
)); 
 265 TimeZoneTest::testUsingBinarySearch(const TimeZone
& tz
, 
 266                                     UDate min
, UDate max
, 
 267                                     UDate expectedBoundary
) 
 269     UErrorCode status 
= U_ZERO_ERROR
; 
 270     UBool startsInDST 
= tz
.inDaylightTime(min
, status
); 
 271     if (failure(status
, "TimeZone::inDaylightTime")) return; 
 272     if (tz
.inDaylightTime(max
, status
) == startsInDST
) { 
 273         logln("Error: inDaylightTime(" + dateToString(max
) + ") != " + ((!startsInDST
)?"TRUE":"FALSE")); 
 276     if (failure(status
, "TimeZone::inDaylightTime")) return; 
 277     while ((max 
- min
) > INTERVAL
) { 
 278         UDate mid 
= (min 
+ max
) / 2; 
 279         if (tz
.inDaylightTime(mid
, status
) == startsInDST
) { 
 284         if (failure(status
, "TimeZone::inDaylightTime")) return; 
 286     logln(UnicodeString("Binary Search Before: ") + uprv_floor(0.5 + min
) + " = " + dateToString(min
)); 
 287     logln(UnicodeString("Binary Search After:  ") + uprv_floor(0.5 + max
) + " = " + dateToString(max
)); 
 288     UDate mindelta 
= expectedBoundary 
- min
; 
 289     UDate maxdelta 
= max 
- expectedBoundary
; 
 291         mindelta 
<= INTERVAL 
&& 
 293         maxdelta 
<= INTERVAL
) 
 294         logln(UnicodeString("PASS: Expected bdry:  ") + expectedBoundary 
+ " = " + dateToString(expectedBoundary
)); 
 296         errln(UnicodeString("FAIL: Expected bdry:  ") + expectedBoundary 
+ " = " + dateToString(expectedBoundary
)); 
 299 const UDate 
TimeZoneTest::INTERVAL 
= 100; 
 301 // --------------------------------------------------------------------------------- 
 303 // ------------------------------------- 
 306  * Test the offset of the PRT timezone. 
 309 TimeZoneTest::TestPRTOffset() 
 311     TimeZone
* tz 
= TimeZone::createTimeZone("PRT"); 
 313         errln("FAIL: TimeZone(PRT) is null"); 
 316       int32_t expectedHour 
= -4; 
 317       double expectedOffset 
= (((double)expectedHour
) * millisPerHour
); 
 318       double foundOffset 
= tz
->getRawOffset(); 
 319       int32_t foundHour 
= (int32_t)foundOffset 
/ millisPerHour
; 
 320       if (expectedOffset 
!= foundOffset
) { 
 321         dataerrln("FAIL: Offset for PRT should be %d, found %d", expectedHour
, foundHour
); 
 323         logln("PASS: Offset for PRT should be %d, found %d", expectedHour
, foundHour
); 
 329 // ------------------------------------- 
 332  * Regress a specific bug with a sequence of API calls. 
 335 TimeZoneTest::TestVariousAPI518() 
 337     UErrorCode status 
= U_ZERO_ERROR
; 
 338     TimeZone
* time_zone 
= TimeZone::createTimeZone("PST"); 
 339     UDate d 
= date(97, UCAL_APRIL
, 30); 
 341     logln("The timezone is " + time_zone
->getID(str
)); 
 342     if (!time_zone
->inDaylightTime(d
, status
)) dataerrln("FAIL: inDaylightTime returned FALSE"); 
 343     if (failure(status
, "TimeZone::inDaylightTime", TRUE
)) return; 
 344     if (!time_zone
->useDaylightTime()) dataerrln("FAIL: useDaylightTime returned FALSE"); 
 345     if (time_zone
->getRawOffset() != - 8 * millisPerHour
) dataerrln("FAIL: getRawOffset returned wrong value"); 
 346     GregorianCalendar 
*gc 
= new GregorianCalendar(status
); 
 347     if (U_FAILURE(status
)) { errln("FAIL: Couldn't create GregorianCalendar"); return; } 
 348     gc
->setTime(d
, status
); 
 349     if (U_FAILURE(status
)) { errln("FAIL: GregorianCalendar::setTime failed"); return; } 
 350     if (time_zone
->getOffset(gc
->AD
, gc
->get(UCAL_YEAR
, status
), gc
->get(UCAL_MONTH
, status
), 
 351         gc
->get(UCAL_DATE
, status
), (uint8_t)gc
->get(UCAL_DAY_OF_WEEK
, status
), 0, status
) != - 7 * millisPerHour
) 
 352         dataerrln("FAIL: getOffset returned wrong value"); 
 353     if (U_FAILURE(status
)) { errln("FAIL: GregorianCalendar::set failed"); return; } 
 358 // ------------------------------------- 
 361  * Test the call which retrieves the available IDs. 
 364 TimeZoneTest::TestGetAvailableIDs913() 
 366     UErrorCode ec 
= U_ZERO_ERROR
; 
 369 #ifdef U_USE_TIMEZONE_OBSOLETE_2_8 
 370     // Test legacy API -- remove these tests when the corresponding API goes away (duh) 
 372     const UnicodeString
** ids 
= TimeZone::createAvailableIDs(numIDs
); 
 373     if (ids 
== 0 || numIDs 
< 1) { 
 374         errln("FAIL: createAvailableIDs()"); 
 376         UnicodeString 
buf("TimeZone::createAvailableIDs() = { "); 
 377         for(i
=0; i
<numIDs
; ++i
) { 
 378             if (i
) buf
.append(", "); 
 383         // we own the array; the caller owns the contained strings (yuck) 
 388     ids 
= TimeZone::createAvailableIDs(-8*U_MILLIS_PER_HOUR
, numIDs
); 
 389     if (ids 
== 0 || numIDs 
< 1) { 
 390         errln("FAIL: createAvailableIDs(-8:00)"); 
 392         UnicodeString 
buf("TimeZone::createAvailableIDs(-8:00) = { "); 
 393         for(i
=0; i
<numIDs
; ++i
) { 
 394             if (i
) buf
.append(", "); 
 399         // we own the array; the caller owns the contained strings (yuck) 
 403     ids 
= TimeZone::createAvailableIDs("US", numIDs
); 
 404     if (ids 
== 0 || numIDs 
< 1) { 
 405       errln("FAIL: createAvailableIDs(US) ids=%d, numIDs=%d", ids
, numIDs
); 
 407         UnicodeString 
buf("TimeZone::createAvailableIDs(US) = { "); 
 408         for(i
=0; i
<numIDs
; ++i
) { 
 409             if (i
) buf
.append(", "); 
 414         // we own the array; the caller owns the contained strings (yuck) 
 420     UnicodeString 
*buf 
= new UnicodeString("TimeZone::createEnumeration() = { "); 
 422     StringEnumeration
* s 
= TimeZone::createEnumeration(); 
 424         dataerrln("Unable to create TimeZone enumeration"); 
 427     s_length 
= s
->count(ec
); 
 428     for (i 
= 0; i 
< s_length
;++i
) { 
 429         if (i 
> 0) *buf 
+= ", "; 
 431             *buf 
+= *s
->snext(ec
); 
 433             *buf 
+= UnicodeString(s
->next(NULL
, ec
), ""); 
 437             // replace s with a clone of itself 
 438             StringEnumeration 
*s2 
= s
->clone(); 
 439             if(s2 
== NULL 
|| s_length 
!= s2
->count(ec
)) { 
 440                 errln("TimezoneEnumeration.clone() failed"); 
 450     /* Confirm that the following zones can be retrieved: The first 
 451      * zone, the last zone, and one in-between.  This tests the binary 
 452      * search through the system zone data. 
 455     int32_t middle 
= s_length
/2; 
 456     for (i
=0; i
<s_length
; ++i
) { 
 457         const UnicodeString
* id 
= s
->snext(ec
); 
 458         if (i
==0 || i
==middle 
|| i
==(s_length
-1)) { 
 459         TimeZone 
*z 
= TimeZone::createTimeZone(*id
); 
 461             errln(UnicodeString("FAIL: createTimeZone(") + 
 463         } else if (z
->getID(str
) != *id
) { 
 464             errln(UnicodeString("FAIL: createTimeZone(") + 
 465                   *id 
+ ") -> zone " + str
); 
 467             logln(UnicodeString("OK: createTimeZone(") + 
 468                   *id 
+ ") succeeded"); 
 476     *buf 
+= "TimeZone::createEnumeration(GMT+01:00) = { "; 
 478     s 
= TimeZone::createEnumeration(1 * U_MILLIS_PER_HOUR
); 
 479     s_length 
= s
->count(ec
); 
 480     for (i 
= 0; i 
< s_length
;++i
) { 
 481         if (i 
> 0) *buf 
+= ", "; 
 482         *buf 
+= *s
->snext(ec
); 
 490     *buf 
+= "TimeZone::createEnumeration(US) = { "; 
 492     s 
= TimeZone::createEnumeration("US"); 
 493     s_length 
= s
->count(ec
); 
 494     for (i 
= 0; i 
< s_length
;++i
) { 
 495         if (i 
> 0) *buf 
+= ", "; 
 496         *buf 
+= *s
->snext(ec
); 
 501     TimeZone 
*tz 
= TimeZone::createTimeZone("PST"); 
 502     if (tz 
!= 0) logln("getTimeZone(PST) = " + tz
->getID(str
)); 
 503     else errln("FAIL: getTimeZone(PST) = null"); 
 505     tz 
= TimeZone::createTimeZone("America/Los_Angeles"); 
 506     if (tz 
!= 0) logln("getTimeZone(America/Los_Angeles) = " + tz
->getID(str
)); 
 507     else errln("FAIL: getTimeZone(PST) = null"); 
 511     tz 
= TimeZone::createTimeZone("NON_EXISTENT"); 
 514         errln("FAIL: getTimeZone(NON_EXISTENT) = null"); 
 515     else if (tz
->getID(temp
) != UCAL_UNKNOWN_ZONE_ID
) 
 516         errln("FAIL: getTimeZone(NON_EXISTENT) = " + temp
); 
 524 TimeZoneTest::TestGetAvailableIDsNew() 
 526     UErrorCode ec 
= U_ZERO_ERROR
; 
 527     StringEnumeration 
*any
, *canonical
, *canonicalLoc
; 
 528     StringEnumeration 
*any_US
, *canonical_US
, *canonicalLoc_US
; 
 529     StringEnumeration 
*any_W5
, *any_CA_W5
; 
 530     StringEnumeration 
*any_US_E14
; 
 532     const UnicodeString 
*id1
, *id2
; 
 533     UnicodeString canonicalID
; 
 538     any 
= canonical 
= canonicalLoc 
= any_US 
= canonical_US 
= canonicalLoc_US 
= any_W5 
= any_CA_W5 
= any_US_E14 
= NULL
; 
 540     any 
= TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY
, NULL
, NULL
, ec
); 
 542         dataerrln("Failed to create enumration for ANY"); 
 546     canonical 
= TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL
, NULL
, NULL
, ec
); 
 548         errln("Failed to create enumration for CANONICAL"); 
 552     canonicalLoc 
= TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL_LOCATION
, NULL
, NULL
, ec
); 
 554         errln("Failed to create enumration for CANONICALLOC"); 
 558     any_US 
= TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY
, "US", NULL
, ec
); 
 560         errln("Failed to create enumration for ANY_US"); 
 564     canonical_US 
= TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL
, "US", NULL
, ec
); 
 566         errln("Failed to create enumration for CANONICAL_US"); 
 570     canonicalLoc_US 
= TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL_LOCATION
, "US", NULL
, ec
); 
 572         errln("Failed to create enumration for CANONICALLOC_US"); 
 576     rawOffset 
= (-5)*60*60*1000; 
 577     any_W5 
= TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY
, NULL
, &rawOffset
, ec
); 
 579         errln("Failed to create enumration for ANY_W5"); 
 583     any_CA_W5 
= TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY
, "CA", &rawOffset
, ec
); 
 585         errln("Failed to create enumration for ANY_CA_W5"); 
 589     rawOffset 
= 14*60*60*1000; 
 590     any_US_E14 
= TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY
, "US", &rawOffset
, ec
); 
 592         errln("Failed to create enumration for ANY_US_E14"); 
 596     checkContainsAll(any
, "ANY", canonical
, "CANONICAL"); 
 597     checkContainsAll(canonical
, "CANONICAL", canonicalLoc
, "CANONICALLOC"); 
 599     checkContainsAll(any
, "ANY", any_US
, "ANY_US"); 
 600     checkContainsAll(canonical
, "CANONICAL", canonical_US
, "CANONICAL_US"); 
 601     checkContainsAll(canonicalLoc
, "CANONICALLOC", canonicalLoc_US
, "CANONICALLOC_US"); 
 603     checkContainsAll(any_US
, "ANY_US", canonical_US
, "CANONICAL_US"); 
 604     checkContainsAll(canonical_US
, "CANONICAL_US", canonicalLoc_US
, "CANONICALLOC_US"); 
 606     checkContainsAll(any
, "ANY", any_W5
, "ANY_W5"); 
 607     checkContainsAll(any_W5
, "ANY_W5", any_CA_W5
, "ANY_CA_W5"); 
 609     // And ID in any set, but not in canonical set must not be a canonical ID 
 611     while ((id1 
= any
->snext(ec
)) != NULL
) { 
 613         canonical
->reset(ec
); 
 614         while ((id2 
= canonical
->snext(ec
)) != NULL
) { 
 624             TimeZone::getCanonicalID(*id1
, canonicalID
, isSystemID
, ec
); 
 628             if (*id1 
== canonicalID
) { 
 629                 errln((UnicodeString
)"FAIL: canonicalID [" + *id1 
+ "] is not in CANONICAL"); 
 632                 errln((UnicodeString
)"FAIL: ANY contains non-system ID: " + *id1
); 
 637         errln("Error checking IDs in ANY, but not in CANONICAL"); 
 641     // canonical set must contains only canonical IDs 
 642     canonical
->reset(ec
); 
 643     while ((id1 
= canonical
->snext(ec
)) != NULL
) { 
 644         TimeZone::getCanonicalID(*id1
, canonicalID
, isSystemID
, ec
); 
 648         if (*id1 
!= canonicalID
) { 
 649             errln((UnicodeString
)"FAIL: CANONICAL contains non-canonical ID: " + *id1
); 
 652             errln((UnicodeString
)"FAILE: CANONICAL contains non-system ID: " + *id1
); 
 656         errln("Error checking IDs in CANONICAL"); 
 660     // canonicalLoc set must contain only canonical location IDs 
 661     canonicalLoc
->reset(ec
); 
 662     while ((id1 
= canonicalLoc
->snext(ec
)) != NULL
) { 
 663         TimeZone::getRegion(*id1
, region
, sizeof(region
), ec
); 
 667         if (uprv_strcmp(region
, "001") == 0) { 
 668             errln((UnicodeString
)"FAIL: CANONICALLOC contains non location zone: " + *id1
); 
 672         errln("Error checking IDs in CANONICALLOC"); 
 676     // any_US must contain only US zones 
 678     while ((id1 
= any_US
->snext(ec
)) != NULL
) { 
 679         TimeZone::getRegion(*id1
, region
, sizeof(region
), ec
); 
 683         if (uprv_strcmp(region
, "US") != 0) { 
 684             errln((UnicodeString
)"FAIL: ANY_US contains non-US zone ID: " + *id1
); 
 688         errln("Error checking IDs in ANY_US"); 
 692     // any_W5 must contain only GMT-05:00 zones 
 694     while ((id1 
= any_W5
->snext(ec
)) != NULL
) { 
 695         TimeZone 
*tz 
= TimeZone::createTimeZone(*id1
); 
 696         if (tz
->getRawOffset() != (-5)*60*60*1000) { 
 697             errln((UnicodeString
)"FAIL: ANY_W5 contains a zone whose offset is not -05:00: " + *id1
); 
 702         errln("Error checking IDs in ANY_W5"); 
 706     // No US zone swith GMT+14:00 
 707     zoneCount 
= any_US_E14
->count(ec
); 
 709         errln("Error checking IDs in ANY_US_E14"); 
 711     } else if (zoneCount 
!= 0) { 
 712         errln("FAIL: ANY_US_E14 must be empty"); 
 721     delete canonicalLoc_US
; 
 728 TimeZoneTest::checkContainsAll(StringEnumeration 
*s1
, const char *name1
, 
 729         StringEnumeration 
*s2
, const char *name2
) 
 731     UErrorCode ec 
= U_ZERO_ERROR
; 
 732     const UnicodeString 
*id1
, *id2
; 
 736     while ((id2 
= s2
->snext(ec
)) != NULL
) { 
 739         while ((id1 
= s1
->snext(ec
)) != NULL
) { 
 746             errln((UnicodeString
)"FAIL: " + name1 
+ "does not contain " 
 747                 + *id2 
+ " in " + name2
); 
 752         errln((UnicodeString
)"Error checkContainsAll for " + name1 
+ " - " + name2
); 
 757  * NOTE: As of ICU 2.8, this test confirms that the "tz.alias" 
 758  * file, used to build ICU alias zones, is working.  It also 
 759  * looks at some genuine Olson compatibility IDs. [aliu] 
 761  * This test is problematic. It should really just confirm that 
 762  * the list of compatibility zone IDs exist and are somewhat 
 763  * meaningful (that is, they aren't all aliases of GMT). It goes a 
 764  * bit further -- it hard-codes expectations about zone behavior, 
 765  * when in fact zones are redefined quite frequently. ICU's build 
 766  * process means that it is easy to update ICU to contain the 
 767  * latest Olson zone data, but if a zone tested here changes, then 
 768  * this test will fail.  I have updated the test for 1999j data, 
 769  * but further updates will probably be required. Note that some 
 770  * of the concerts listed below no longer apply -- in particular, 
 771  * we do NOT overwrite real UNIX zones with 3-letter IDs. There 
 772  * are two points of overlap as of 1999j: MET and EET. These are 
 773  * both real UNIX zones, so we just use the official 
 774  * definition. This test has been updated to reflect this. 
 777  * Added tests for additional zones and aliases from the icuzones file. 
 778  * Markus Scherer 2006-nov-06 
 780  * [srl - from java - 7/5/1998] 
 782  * Certain short zone IDs, used since 1.1.x, are incorrect. 
 784  * The worst of these is: 
 786  * "CAT" (Central African Time) should be GMT+2:00, but instead returns a 
 787  * zone at GMT-1:00. The zone at GMT-1:00 should be called EGT, CVT, EGST, 
 788  * or AZOST, depending on which zone is meant, but in no case is it CAT. 
 790  * Other wrong zone IDs: 
 792  * ECT (European Central Time) GMT+1:00: ECT is Ecuador Time, 
 793  * GMT-5:00. European Central time is abbreviated CEST. 
 795  * SST (Solomon Island Time) GMT+11:00. SST is actually Samoa Standard Time, 
 796  * GMT-11:00. Solomon Island time is SBT. 
 798  * NST (New Zealand Time) GMT+12:00. NST is the abbreviation for 
 799  * Newfoundland Standard Time, GMT-3:30. New Zealanders use NZST. 
 801  * AST (Alaska Standard Time) GMT-9:00. [This has already been noted in 
 802  * another bug.] It should be "AKST". AST is Atlantic Standard Time, 
 805  * PNT (Phoenix Time) GMT-7:00. PNT usually means Pitcairn Time, 
 806  * GMT-8:30. There is no standard abbreviation for Phoenix time, as distinct 
 807  * from MST with daylight savings. 
 809  * In addition to these problems, a number of zones are FAKE. That is, they 
 810  * don't match what people use in the real world. 
 814  * EET (should be EEST) 
 815  * ART (should be EEST) 
 816  * MET (should be IRST) 
 817  * NET (should be AMST) 
 818  * PLT (should be PKT) 
 819  * BST (should be BDT) 
 820  * VST (should be ICT) 
 821  * CTT (should be CST) + 
 822  * ACT (should be CST) + 
 823  * AET (should be EST) + 
 824  * MIT (should be WST) + 
 825  * IET (should be EST) + 
 826  * PRT (should be AST) + 
 827  * CNT (should be NST) 
 828  * AGT (should be ARST) 
 829  * BET (should be EST) + 
 831  * + A zone with the correct name already exists and means something 
 832  * else. E.g., EST usually indicates the US Eastern zone, so it cannot be 
 833  * used for Brazil (BET). 
 835 void TimeZoneTest::TestShortZoneIDs() 
 838     // Create a small struct to hold the array 
 847         {"HST", -600, FALSE
}, // Olson northamerica -10:00 
 848         {"AST", -540, TRUE
},  // ICU Link - America/Anchorage 
 849         {"PST", -480, TRUE
},  // ICU Link - America/Los_Angeles 
 850         {"PNT", -420, FALSE
}, // ICU Link - America/Phoenix 
 851         {"MST", -420, FALSE
}, // updated Aug 2003 aliu 
 852         {"CST", -360, TRUE
},  // Olson northamerica -7:00 
 853         {"IET", -300, TRUE
},  // ICU Link - America/Indiana/Indianapolis 
 854         {"EST", -300, FALSE
}, // Olson northamerica -5:00 
 855         {"PRT", -240, FALSE
}, // ICU Link - America/Puerto_Rico 
 856         {"CNT", -210, TRUE
},  // ICU Link - America/St_Johns 
 857         {"AGT", -180, FALSE
}, // ICU Link - America/Argentina/Buenos_Aires 
 858         {"BET", -180, TRUE
},  // ICU Link - America/Sao_Paulo 
 859         {"GMT", 0, FALSE
},    // Olson etcetera Link - Etc/GMT 
 860         {"UTC", 0, FALSE
},    // Olson etcetera 0 
 861         {"ECT", 60, TRUE
},    // ICU Link - Europe/Paris 
 862         {"MET", 60, TRUE
},    // Olson europe 1:00 C-Eur 
 863         {"CAT", 120, FALSE
},  // ICU Link - Africa/Maputo 
 864         {"ART", 120, FALSE
},  // ICU Link - Africa/Cairo 
 865         {"EET", 120, TRUE
},   // Olson europe 2:00 EU 
 866         {"EAT", 180, FALSE
},  // ICU Link - Africa/Addis_Ababa 
 867         {"NET", 240, FALSE
},  // ICU Link - Asia/Yerevan 
 868         {"PLT", 300, FALSE
},  // ICU Link - Asia/Karachi 
 869         {"IST", 330, FALSE
},  // ICU Link - Asia/Kolkata 
 870         {"BST", 360, FALSE
},  // ICU Link - Asia/Dhaka 
 871         {"VST", 420, FALSE
},  // ICU Link - Asia/Ho_Chi_Minh 
 872         {"CTT", 480, FALSE
},  // ICU Link - Asia/Shanghai 
 873         {"JST", 540, FALSE
},  // ICU Link - Asia/Tokyo 
 874         {"ACT", 570, FALSE
},  // ICU Link - Australia/Darwin 
 875         {"AET", 600, TRUE
},   // ICU Link - Australia/Sydney 
 876         {"SST", 660, FALSE
},  // ICU Link - Pacific/Guadalcanal 
 877         {"NST", 720, TRUE
},   // ICU Link - Pacific/Auckland 
 878         {"MIT", 780, TRUE
},   // ICU Link - Pacific/Apia 
 880         {"Etc/Unknown", 0, FALSE
},  // CLDR 
 882         {"SystemV/AST4ADT", -240, TRUE
}, 
 883         {"SystemV/EST5EDT", -300, TRUE
}, 
 884         {"SystemV/CST6CDT", -360, TRUE
}, 
 885         {"SystemV/MST7MDT", -420, TRUE
}, 
 886         {"SystemV/PST8PDT", -480, TRUE
}, 
 887         {"SystemV/YST9YDT", -540, TRUE
}, 
 888         {"SystemV/AST4", -240, FALSE
}, 
 889         {"SystemV/EST5", -300, FALSE
}, 
 890         {"SystemV/CST6", -360, FALSE
}, 
 891         {"SystemV/MST7", -420, FALSE
}, 
 892         {"SystemV/PST8", -480, FALSE
}, 
 893         {"SystemV/YST9", -540, FALSE
}, 
 894         {"SystemV/HST10", -600, FALSE
}, 
 899     for(i
=0;kReferenceList
[i
].id
[0];i
++) { 
 900         UnicodeString 
itsID(kReferenceList
[i
].id
); 
 903         TimeZone 
*tz 
= TimeZone::createTimeZone(itsID
); 
 904         if (!tz 
|| (kReferenceList
[i
].offset 
!= 0 && *tz 
== *TimeZone::getGMT())) { 
 905             errln("FAIL: Time Zone " + itsID 
+ " does not exist!"); 
 909         // Check daylight usage. 
 910         UBool usesDaylight 
= tz
->useDaylightTime(); 
 911         if (usesDaylight 
!= kReferenceList
[i
].daylight
) { 
 912             if (!isDevelopmentBuild
) { 
 913                 logln("Warning: Time Zone " + itsID 
+ " use daylight is " + 
 914                       (usesDaylight
?"TRUE":"FALSE") + 
 915                       " but it should be " + 
 916                       ((kReferenceList
[i
].daylight
)?"TRUE":"FALSE")); 
 918                 dataerrln("FAIL: Time Zone " + itsID 
+ " use daylight is " + 
 919                       (usesDaylight
?"TRUE":"FALSE") + 
 920                       " but it should be " + 
 921                       ((kReferenceList
[i
].daylight
)?"TRUE":"FALSE")); 
 927         int32_t offsetInMinutes 
= tz
->getRawOffset()/60000; 
 928         if (offsetInMinutes 
!= kReferenceList
[i
].offset
) { 
 929             if (!isDevelopmentBuild
) { 
 930                 logln("FAIL: Time Zone " + itsID 
+ " raw offset is " + 
 932                       " but it should be " + kReferenceList
[i
].offset
); 
 934                 dataerrln("FAIL: Time Zone " + itsID 
+ " raw offset is " + 
 936                       " but it should be " + kReferenceList
[i
].offset
); 
 942             logln("OK: " + itsID 
+ 
 943                   " useDaylightTime() & getRawOffset() as expected"); 
 949     // OK now test compat 
 950     logln("Testing for compatibility zones"); 
 952     const char* compatibilityMap
[] = { 
 953         // This list is copied from tz.alias.  If tz.alias 
 954         // changes, this list must be updated.  Current as of Mar 2007 
 955         "ACT", "Australia/Darwin", 
 956         "AET", "Australia/Sydney", 
 957         "AGT", "America/Buenos_Aires", 
 958         "ART", "Africa/Cairo", 
 959         "AST", "America/Anchorage", 
 960         "BET", "America/Sao_Paulo", 
 961         "BST", "Asia/Dhaka", // # spelling changed in 2000h; was Asia/Dacca 
 962         "CAT", "Africa/Maputo", 
 963         "CNT", "America/St_Johns", 
 964         "CST", "America/Chicago", 
 965         "CTT", "Asia/Shanghai", 
 966         "EAT", "Africa/Addis_Ababa", 
 967         "ECT", "Europe/Paris", 
 968         // EET Europe/Istanbul # EET is a standard UNIX zone 
 969         // "EST", "America/New_York", # Defined as -05:00 
 970         // "HST", "Pacific/Honolulu", # Defined as -10:00 
 971         "IET", "America/Indianapolis", 
 972         "IST", "Asia/Calcutta", 
 974         // MET Asia/Tehran # MET is a standard UNIX zone 
 975         "MIT", "Pacific/Apia", 
 976         // "MST", "America/Denver", # Defined as -07:00 
 977         "NET", "Asia/Yerevan", 
 978         "NST", "Pacific/Auckland", 
 979         "PLT", "Asia/Karachi", 
 980         "PNT", "America/Phoenix", 
 981         "PRT", "America/Puerto_Rico", 
 982         "PST", "America/Los_Angeles", 
 983         "SST", "Pacific/Guadalcanal", 
 985         "VST", "Asia/Saigon", 
 989     for (i
=0;*compatibilityMap
[i
];i
+=2) { 
 992         const char *zone1 
= compatibilityMap
[i
]; 
 993         const char *zone2 
= compatibilityMap
[i
+1]; 
 995         TimeZone 
*tz1 
= TimeZone::createTimeZone(zone1
); 
 996         TimeZone 
*tz2 
= TimeZone::createTimeZone(zone2
); 
 999             errln(UnicodeString("FAIL: Could not find short ID zone ") + zone1
); 
1002             errln(UnicodeString("FAIL: Could not find long ID zone ") + zone2
); 
1006             // make NAME same so comparison will only look at the rest 
1007             tz2
->setID(tz1
->getID(itsID
)); 
1010                 errln("FAIL: " + UnicodeString(zone1
) + 
1011                       " != " + UnicodeString(zone2
)); 
1013                 logln("OK: " + UnicodeString(zone1
) + 
1014                       " == " + UnicodeString(zone2
)); 
1025  * Utility function for TestCustomParse 
1027 UnicodeString
& TimeZoneTest::formatOffset(int32_t offset
, UnicodeString 
&rv
) { 
1029     UChar sign 
= 0x002B; 
1035     int32_t s 
= offset 
% 60; 
1037     int32_t m 
= offset 
% 60; 
1038     int32_t h 
= offset 
/ 60; 
1040     rv 
+= (UChar
)(sign
); 
1042         rv 
+= (UChar
)(0x0030 + (h
/10)); 
1044         rv 
+= (UChar
)0x0030; 
1046     rv 
+= (UChar
)(0x0030 + (h%10
)); 
1048     rv 
+= (UChar
)0x003A; /* ':' */ 
1050         rv 
+= (UChar
)(0x0030 + (m
/10)); 
1052         rv 
+= (UChar
)0x0030; 
1054     rv 
+= (UChar
)(0x0030 + (m%10
)); 
1057         rv 
+= (UChar
)0x003A; /* ':' */ 
1059             rv 
+= (UChar
)(0x0030 + (s
/10)); 
1061             rv 
+= (UChar
)0x0030; 
1063         rv 
+= (UChar
)(0x0030 + (s%10
)); 
1069  * Utility function for TestCustomParse, generating time zone ID 
1070  * string for the give offset. 
1072 UnicodeString
& TimeZoneTest::formatTZID(int32_t offset
, UnicodeString 
&rv
) { 
1074     UChar sign 
= 0x002B; 
1080     int32_t s 
= offset 
% 60; 
1082     int32_t m 
= offset 
% 60; 
1083     int32_t h 
= offset 
/ 60; 
1086     rv 
+= (UChar
)(sign
); 
1088         rv 
+= (UChar
)(0x0030 + (h
/10)); 
1090         rv 
+= (UChar
)0x0030; 
1092     rv 
+= (UChar
)(0x0030 + (h%10
)); 
1093     rv 
+= (UChar
)0x003A; 
1095         rv 
+= (UChar
)(0x0030 + (m
/10)); 
1097         rv 
+= (UChar
)0x0030; 
1099     rv 
+= (UChar
)(0x0030 + (m%10
)); 
1102         rv 
+= (UChar
)0x003A; 
1104             rv 
+= (UChar
)(0x0030 + (s
/10)); 
1106             rv 
+= (UChar
)0x0030; 
1108         rv 
+= (UChar
)(0x0030 + (s%10
)); 
1114  * As part of the VM fix (see CCC approved RFE 4028006, bug 
1115  * 4044013), TimeZone.getTimeZone() has been modified to recognize 
1116  * generic IDs of the form GMT[+-]hh:mm, GMT[+-]hhmm, and 
1117  * GMT[+-]hh.  Test this behavior here. 
1121 void TimeZoneTest::TestCustomParse() 
1124     const int32_t kUnparseable 
= 604800; // the number of seconds in a week. More than any offset should be. 
1128         const char *customId
; 
1129         int32_t expectedOffset
; 
1133         // ID        Expected offset in seconds 
1134         {"GMT",       kUnparseable
},   //Isn't custom. [returns normal GMT] 
1135         {"GMT-YOUR.AD.HERE", kUnparseable
}, 
1136         {"GMT0",      kUnparseable
}, 
1138         {"GMT+1",     (1*60*60)}, 
1139         {"GMT-0030",  (-30*60)}, 
1140         {"GMT+15:99", kUnparseable
}, 
1141         {"GMT+",      kUnparseable
}, 
1142         {"GMT-",      kUnparseable
}, 
1143         {"GMT+0:",    kUnparseable
}, 
1144         {"GMT-:",     kUnparseable
}, 
1145         {"GMT-YOUR.AD.HERE",    kUnparseable
}, 
1146         {"GMT+0010",  (10*60)}, // Interpret this as 00:10 
1147         {"GMT-10",    (-10*60*60)}, 
1148         {"GMT+30",    kUnparseable
}, 
1149         {"GMT-3:30",  (-(3*60+30)*60)}, 
1150         {"GMT-230",   (-(2*60+30)*60)}, 
1151         {"GMT+05:13:05",    ((5*60+13)*60+5)}, 
1152         {"GMT-71023",       (-((7*60+10)*60+23))}, 
1153         {"GMT+01:23:45:67", kUnparseable
}, 
1154         {"GMT+01:234",      kUnparseable
}, 
1155         {"GMT-2:31:123",    kUnparseable
}, 
1156         {"GMT+3:75",        kUnparseable
}, 
1157         {"GMT-01010101",    kUnparseable
}, 
1161     for (i
=0; kData
[i
].customId 
!= 0; i
++) { 
1162         UnicodeString 
id(kData
[i
].customId
); 
1163         int32_t exp 
= kData
[i
].expectedOffset
; 
1164         TimeZone 
*zone 
= TimeZone::createTimeZone(id
); 
1165         UnicodeString   itsID
, temp
; 
1167         if (dynamic_cast<OlsonTimeZone 
*>(zone
) != NULL
) { 
1168             logln(id 
+ " -> Olson time zone"); 
1171             int32_t ioffset 
= zone
->getRawOffset()/1000; 
1172             UnicodeString offset
, expectedID
; 
1173             formatOffset(ioffset
, offset
); 
1174             formatTZID(ioffset
, expectedID
); 
1175             logln(id 
+ " -> " + itsID 
+ " " + offset
); 
1176             if (exp 
== kUnparseable 
&& itsID 
!= UCAL_UNKNOWN_ZONE_ID
) { 
1177                 errln("Expected parse failure for " + id 
+ 
1178                       ", got offset of " + offset 
+ 
1181             // JDK 1.3 creates custom zones with the ID "Custom" 
1182             // JDK 1.4 creates custom zones with IDs of the form "GMT+02:00" 
1183             // ICU creates custom zones with IDs of the form "GMT+02:00" 
1184             else if (exp 
!= kUnparseable 
&& (ioffset 
!= exp 
|| itsID 
!= expectedID
)) { 
1185                 dataerrln("Expected offset of " + formatOffset(exp
, temp
) + 
1186                       ", id " + expectedID 
+ 
1188                       ", got offset of " + offset 
+ 
1197 TimeZoneTest::TestAliasedNames() 
1203         /* Generated by org.unicode.cldr.tool.CountItems */ 
1205         /* zoneID, canonical zoneID */ 
1206         {"Africa/Timbuktu", "Africa/Bamako"}, 
1207         {"America/Argentina/Buenos_Aires", "America/Buenos_Aires"}, 
1208         {"America/Argentina/Catamarca", "America/Catamarca"}, 
1209         {"America/Argentina/ComodRivadavia", "America/Catamarca"}, 
1210         {"America/Argentina/Cordoba", "America/Cordoba"}, 
1211         {"America/Argentina/Jujuy", "America/Jujuy"}, 
1212         {"America/Argentina/Mendoza", "America/Mendoza"}, 
1213         {"America/Atka", "America/Adak"}, 
1214         {"America/Ensenada", "America/Tijuana"}, 
1215         {"America/Fort_Wayne", "America/Indiana/Indianapolis"}, 
1216         {"America/Indianapolis", "America/Indiana/Indianapolis"}, 
1217         {"America/Knox_IN", "America/Indiana/Knox"}, 
1218         {"America/Louisville", "America/Kentucky/Louisville"}, 
1219         {"America/Porto_Acre", "America/Rio_Branco"}, 
1220         {"America/Rosario", "America/Cordoba"}, 
1221         {"America/Virgin", "America/St_Thomas"}, 
1222         {"Asia/Ashkhabad", "Asia/Ashgabat"}, 
1223         {"Asia/Chungking", "Asia/Chongqing"}, 
1224         {"Asia/Dacca", "Asia/Dhaka"}, 
1225         {"Asia/Istanbul", "Europe/Istanbul"}, 
1226         {"Asia/Macao", "Asia/Macau"}, 
1227         {"Asia/Tel_Aviv", "Asia/Jerusalem"}, 
1228         {"Asia/Thimbu", "Asia/Thimphu"}, 
1229         {"Asia/Ujung_Pandang", "Asia/Makassar"}, 
1230         {"Asia/Ulan_Bator", "Asia/Ulaanbaatar"}, 
1231         {"Australia/ACT", "Australia/Sydney"}, 
1232         {"Australia/Canberra", "Australia/Sydney"}, 
1233         {"Australia/LHI", "Australia/Lord_Howe"}, 
1234         {"Australia/NSW", "Australia/Sydney"}, 
1235         {"Australia/North", "Australia/Darwin"}, 
1236         {"Australia/Queensland", "Australia/Brisbane"}, 
1237         {"Australia/South", "Australia/Adelaide"}, 
1238         {"Australia/Tasmania", "Australia/Hobart"}, 
1239         {"Australia/Victoria", "Australia/Melbourne"}, 
1240         {"Australia/West", "Australia/Perth"}, 
1241         {"Australia/Yancowinna", "Australia/Broken_Hill"}, 
1242         {"Brazil/Acre", "America/Rio_Branco"}, 
1243         {"Brazil/DeNoronha", "America/Noronha"}, 
1244         {"Brazil/East", "America/Sao_Paulo"}, 
1245         {"Brazil/West", "America/Manaus"}, 
1246         {"Canada/Atlantic", "America/Halifax"}, 
1247         {"Canada/Central", "America/Winnipeg"}, 
1248         {"Canada/East-Saskatchewan", "America/Regina"}, 
1249         {"Canada/Eastern", "America/Toronto"}, 
1250         {"Canada/Mountain", "America/Edmonton"}, 
1251         {"Canada/Newfoundland", "America/St_Johns"}, 
1252         {"Canada/Pacific", "America/Vancouver"}, 
1253         {"Canada/Saskatchewan", "America/Regina"}, 
1254         {"Canada/Yukon", "America/Whitehorse"}, 
1255         {"Chile/Continental", "America/Santiago"}, 
1256         {"Chile/EasterIsland", "Pacific/Easter"}, 
1257         {"Cuba", "America/Havana"}, 
1258         {"Egypt", "Africa/Cairo"}, 
1259         {"Eire", "Europe/Dublin"}, 
1260         {"Etc/GMT+0", "Etc/GMT"}, 
1261         {"Etc/GMT-0", "Etc/GMT"}, 
1262         {"Etc/GMT0", "Etc/GMT"}, 
1263         {"Etc/Greenwich", "Etc/GMT"}, 
1264         {"Etc/UCT", "Etc/GMT"}, 
1265         {"Etc/UTC", "Etc/GMT"}, 
1266         {"Etc/Universal", "Etc/GMT"}, 
1267         {"Etc/Zulu", "Etc/GMT"}, 
1268         {"Europe/Belfast", "Europe/London"}, 
1269         {"Europe/Nicosia", "Asia/Nicosia"}, 
1270         {"Europe/Tiraspol", "Europe/Chisinau"}, 
1271         {"GB", "Europe/London"}, 
1272         {"GB-Eire", "Europe/London"}, 
1274         {"GMT+0", "Etc/GMT"}, 
1275         {"GMT-0", "Etc/GMT"}, 
1276         {"GMT0", "Etc/GMT"}, 
1277         {"Greenwich", "Etc/GMT"}, 
1278         {"Hongkong", "Asia/Hong_Kong"}, 
1279         {"Iceland", "Atlantic/Reykjavik"}, 
1280         {"Iran", "Asia/Tehran"}, 
1281         {"Israel", "Asia/Jerusalem"}, 
1282         {"Jamaica", "America/Jamaica"}, 
1283         {"Japan", "Asia/Tokyo"}, 
1284         {"Kwajalein", "Pacific/Kwajalein"}, 
1285         {"Libya", "Africa/Tripoli"}, 
1286         {"Mexico/BajaNorte", "America/Tijuana"}, 
1287         {"Mexico/BajaSur", "America/Mazatlan"}, 
1288         {"Mexico/General", "America/Mexico_City"}, 
1289         {"NZ", "Pacific/Auckland"}, 
1290         {"NZ-CHAT", "Pacific/Chatham"}, 
1291         {"Navajo", "America/Shiprock"}, 
1292         {"PRC", "Asia/Shanghai"}, 
1293         {"Pacific/Samoa", "Pacific/Pago_Pago"}, 
1294         {"Pacific/Yap", "Pacific/Truk"}, 
1295         {"Poland", "Europe/Warsaw"}, 
1296         {"Portugal", "Europe/Lisbon"}, 
1297         {"ROC", "Asia/Taipei"}, 
1298         {"ROK", "Asia/Seoul"}, 
1299         {"Singapore", "Asia/Singapore"}, 
1300         {"Turkey", "Europe/Istanbul"}, 
1302         {"US/Alaska", "America/Anchorage"}, 
1303         {"US/Aleutian", "America/Adak"}, 
1304         {"US/Arizona", "America/Phoenix"}, 
1305         {"US/Central", "America/Chicago"}, 
1306         {"US/East-Indiana", "America/Indiana/Indianapolis"}, 
1307         {"US/Eastern", "America/New_York"}, 
1308         {"US/Hawaii", "Pacific/Honolulu"}, 
1309         {"US/Indiana-Starke", "America/Indiana/Knox"}, 
1310         {"US/Michigan", "America/Detroit"}, 
1311         {"US/Mountain", "America/Denver"}, 
1312         {"US/Pacific", "America/Los_Angeles"}, 
1313         {"US/Pacific-New", "America/Los_Angeles"}, 
1314         {"US/Samoa", "Pacific/Pago_Pago"}, 
1316         {"Universal", "Etc/GMT"}, 
1317         {"W-SU", "Europe/Moscow"}, 
1318         {"Zulu", "Etc/GMT"}, 
1323     TimeZone::EDisplayType styles
[] = { TimeZone::SHORT
, TimeZone::LONG 
}; 
1324     UBool useDst
[] = { FALSE
, TRUE 
}; 
1325     int32_t noLoc 
= uloc_countAvailable(); 
1327     int32_t i
, j
, k
, loc
; 
1328     UnicodeString fromName
, toName
; 
1329     TimeZone 
*from 
= NULL
, *to 
= NULL
; 
1330     for(i 
= 0; i 
< (int32_t)(sizeof(kData
)/sizeof(kData
[0])); i
++) { 
1331         from 
= TimeZone::createTimeZone(kData
[i
].from
); 
1332         to 
= TimeZone::createTimeZone(kData
[i
].to
); 
1333         if(!from
->hasSameRules(*to
)) { 
1334             errln("different at %i\n", i
); 
1337             for(loc 
= 0; loc 
< noLoc
; loc
++) { 
1338                 const char* locale 
= uloc_getAvailable(loc
);  
1339                 for(j 
= 0; j 
< (int32_t)(sizeof(styles
)/sizeof(styles
[0])); j
++) { 
1340                     for(k 
= 0; k 
< (int32_t)(sizeof(useDst
)/sizeof(useDst
[0])); k
++) { 
1343                         from
->getDisplayName(useDst
[k
], styles
[j
],locale
, fromName
); 
1344                         to
->getDisplayName(useDst
[k
], styles
[j
], locale
, toName
); 
1345                         if(fromName
.compare(toName
) != 0) { 
1346                             errln("Fail: Expected "+toName
+" but got " + prettify(fromName
)  
1347                                 + " for locale: " + locale 
+ " index: "+ loc 
 
1348                                 + " to id "+ kData
[i
].to
 
1349                                 + " from id " + kData
[i
].from
); 
1357             from
->getDisplayName(fromName
); 
1358             to
->getDisplayName(toName
); 
1359             if(fromName
.compare(toName
) != 0) { 
1360                 errln("Fail: Expected "+toName
+" but got " + fromName
); 
1369  * Test the basic functionality of the getDisplayName() API. 
1374  * See also API change request A41. 
1376  * 4/21/98 - make smarter, so the test works if the ext resources 
1377  * are present or not. 
1380 TimeZoneTest::TestDisplayName() 
1382     UErrorCode status 
= U_ZERO_ERROR
; 
1384     TimeZone 
*zone 
= TimeZone::createTimeZone("PST"); 
1386     zone
->getDisplayName(Locale::getEnglish(), name
); 
1387     logln("PST->" + name
); 
1388     if (name
.compare("Pacific Standard Time") != 0) 
1389         dataerrln("Fail: Expected \"Pacific Standard Time\" but got " + name
); 
1391     //***************************************************************** 
1392     // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES 
1393     // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES 
1394     // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES 
1395     //***************************************************************** 
1399         TimeZone::EDisplayType style
; 
1402         {FALSE
, TimeZone::SHORT
, "PST"}, 
1403         {TRUE
,  TimeZone::SHORT
, "PDT"}, 
1404         {FALSE
, TimeZone::LONG
,  "Pacific Standard Time"}, 
1405         {TRUE
,  TimeZone::LONG
,  "Pacific Daylight Time"}, 
1407         {FALSE
, TimeZone::SHORT_GENERIC
, "PT"}, 
1408         {TRUE
,  TimeZone::SHORT_GENERIC
, "PT"}, 
1409         {FALSE
, TimeZone::LONG_GENERIC
,  "Pacific Time"}, 
1410         {TRUE
,  TimeZone::LONG_GENERIC
,  "Pacific Time"}, 
1412         {FALSE
, TimeZone::SHORT_GMT
, "-0800"}, 
1413         {TRUE
,  TimeZone::SHORT_GMT
, "-0700"}, 
1414         {FALSE
, TimeZone::LONG_GMT
,  "GMT-08:00"}, 
1415         {TRUE
,  TimeZone::LONG_GMT
,  "GMT-07:00"}, 
1417         {FALSE
, TimeZone::SHORT_COMMONLY_USED
, "PST"}, 
1418         {TRUE
,  TimeZone::SHORT_COMMONLY_USED
, "PDT"}, 
1419         {FALSE
, TimeZone::GENERIC_LOCATION
,  "Los Angeles Time"}, 
1420         {TRUE
,  TimeZone::GENERIC_LOCATION
,  "Los Angeles Time"}, 
1422         {FALSE
, TimeZone::LONG
, ""} 
1425     for (i
=0; kData
[i
].expect
[0] != '\0'; i
++) 
1428         name 
= zone
->getDisplayName(kData
[i
].useDst
, 
1430                                    Locale::getEnglish(), name
); 
1431         if (name
.compare(kData
[i
].expect
) != 0) 
1432             dataerrln("Fail: Expected " + UnicodeString(kData
[i
].expect
) + "; got " + name
); 
1433         logln("PST [with options]->" + name
); 
1435     for (i
=0; kData
[i
].expect
[0] != '\0'; i
++) 
1438         name 
= zone
->getDisplayName(kData
[i
].useDst
, 
1439                                    kData
[i
].style
, name
); 
1440         if (name
.compare(kData
[i
].expect
) != 0) 
1441             dataerrln("Fail: Expected " + UnicodeString(kData
[i
].expect
) + "; got " + name
); 
1442         logln("PST [with options]->" + name
); 
1446     // Make sure that we don't display the DST name by constructing a fake 
1447     // PST zone that has DST all year long. 
1448     SimpleTimeZone 
*zone2 
= new SimpleTimeZone(0, "PST"); 
1450     zone2
->setStartRule(UCAL_JANUARY
, 1, 0, 0, status
); 
1451     zone2
->setEndRule(UCAL_DECEMBER
, 31, 0, 0, status
); 
1453     UnicodeString inDaylight
; 
1454     if (zone2
->inDaylightTime(UDate(0), status
)) { 
1455         inDaylight 
= UnicodeString("TRUE"); 
1457         inDaylight 
= UnicodeString("FALSE"); 
1459     logln(UnicodeString("Modified PST inDaylightTime->") + inDaylight 
); 
1460     if(U_FAILURE(status
)) 
1462         dataerrln("Some sort of error..." + UnicodeString(u_errorName(status
))); // REVISIT 
1465     name 
= zone2
->getDisplayName(Locale::getEnglish(),name
); 
1466     logln("Modified PST->" + name
); 
1467     if (name
.compare("Pacific Standard Time") != 0) 
1468         dataerrln("Fail: Expected \"Pacific Standard Time\""); 
1470     // Make sure we get the default display format for Locales 
1471     // with no display name data. 
1472     Locale 
mt_MT("mt_MT"); 
1474     name 
= zone
->getDisplayName(mt_MT
,name
); 
1475     //***************************************************************** 
1476     // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES 
1477     // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES 
1478     // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES 
1479     //***************************************************************** 
1480     logln("PST(mt_MT)->" + name
); 
1482     // *** REVISIT SRL how in the world do I check this? looks java specific. 
1483     // Now be smart -- check to see if zh resource is even present. 
1484     // If not, we expect the en fallback behavior. 
1485     ResourceBundle 
enRB(NULL
, 
1486                             Locale::getEnglish(), status
); 
1487     if(U_FAILURE(status
)) 
1488         dataerrln("Couldn't get ResourceBundle for en - %s", u_errorName(status
)); 
1490     ResourceBundle 
mtRB(NULL
, 
1492     //if(U_FAILURE(status)) 
1493     //    errln("Couldn't get ResourceBundle for mt_MT"); 
1495     UBool noZH 
= U_FAILURE(status
); 
1498         logln("Warning: Not testing the mt_MT behavior because resource is absent"); 
1499         if (name 
!= "Pacific Standard Time") 
1500             dataerrln("Fail: Expected Pacific Standard Time"); 
1504     if      (name
.compare("GMT-08:00") && 
1505              name
.compare("GMT-8:00") && 
1506              name
.compare("GMT-0800") && 
1507              name
.compare("GMT-800")) { 
1508       dataerrln(UnicodeString("Fail: Expected GMT-08:00 or something similar for PST in mt_MT but got ") + name 
); 
1509         dataerrln("************************************************************"); 
1510         dataerrln("THE ABOVE FAILURE MAY JUST MEAN THE LOCALE DATA HAS CHANGED"); 
1511         dataerrln("************************************************************"); 
1514     // Now try a non-existent zone 
1516     zone2 
= new SimpleTimeZone(90*60*1000, "xyzzy"); 
1518     name 
= zone2
->getDisplayName(Locale::getEnglish(),name
); 
1519     logln("GMT+90min->" + name
); 
1520     if (name
.compare("GMT+01:30") && 
1521         name
.compare("GMT+1:30") && 
1522         name
.compare("GMT+0130") && 
1523         name
.compare("GMT+130")) 
1524         dataerrln("Fail: Expected GMT+01:30 or something similar"); 
1526     zone2
->getDisplayName(name
); 
1527     logln("GMT+90min->" + name
); 
1528     if (name
.compare("GMT+01:30") && 
1529         name
.compare("GMT+1:30") && 
1530         name
.compare("GMT+0130") && 
1531         name
.compare("GMT+130")) 
1532         dataerrln("Fail: Expected GMT+01:30 or something similar"); 
1542 TimeZoneTest::TestDSTSavings() 
1544     UErrorCode status 
= U_ZERO_ERROR
; 
1545     // It might be better to find a way to integrate this test into the main TimeZone 
1546     // tests above, but I don't have time to figure out how to do this (or if it's 
1547     // even really a good idea).  Let's consider that a future.  --rtg 1/27/98 
1548     SimpleTimeZone 
*tz 
= new SimpleTimeZone(-5 * U_MILLIS_PER_HOUR
, "dstSavingsTest", 
1549                                            UCAL_MARCH
, 1, 0, 0, UCAL_SEPTEMBER
, 1, 0, 0, 
1550                                            (int32_t)(0.5 * U_MILLIS_PER_HOUR
), status
); 
1551     if(U_FAILURE(status
)) 
1552         errln("couldn't create TimeZone"); 
1554     if (tz
->getRawOffset() != -5 * U_MILLIS_PER_HOUR
) 
1555         errln(UnicodeString("Got back a raw offset of ") + (tz
->getRawOffset() / U_MILLIS_PER_HOUR
) + 
1556               " hours instead of -5 hours."); 
1557     if (!tz
->useDaylightTime()) 
1558         errln("Test time zone should use DST but claims it doesn't."); 
1559     if (tz
->getDSTSavings() != 0.5 * U_MILLIS_PER_HOUR
) 
1560         errln(UnicodeString("Set DST offset to 0.5 hour, but got back ") + (tz
->getDSTSavings() / 
1561                                                              U_MILLIS_PER_HOUR
) + " hours instead."); 
1563     int32_t offset 
= tz
->getOffset(GregorianCalendar::AD
, 1998, UCAL_JANUARY
, 1, 
1564                               UCAL_THURSDAY
, 10 * U_MILLIS_PER_HOUR
,status
); 
1565     if (offset 
!= -5 * U_MILLIS_PER_HOUR
) 
1566         errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ") 
1567               + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1569     offset 
= tz
->getOffset(GregorianCalendar::AD
, 1998, UCAL_JUNE
, 1, UCAL_MONDAY
, 
1570                           10 * U_MILLIS_PER_HOUR
,status
); 
1571     if (offset 
!= -4.5 * U_MILLIS_PER_HOUR
) 
1572         errln(UnicodeString("The offset for 10 AM, 6/1/98 should have been -4.5 hours, but we got ") 
1573               + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1575     tz
->setDSTSavings(U_MILLIS_PER_HOUR
, status
); 
1576     offset 
= tz
->getOffset(GregorianCalendar::AD
, 1998, UCAL_JANUARY
, 1, 
1577                           UCAL_THURSDAY
, 10 * U_MILLIS_PER_HOUR
,status
); 
1578     if (offset 
!= -5 * U_MILLIS_PER_HOUR
) 
1579         errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ") 
1580               + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1582     offset 
= tz
->getOffset(GregorianCalendar::AD
, 1998, UCAL_JUNE
, 1, UCAL_MONDAY
, 
1583                           10 * U_MILLIS_PER_HOUR
,status
); 
1584     if (offset 
!= -4 * U_MILLIS_PER_HOUR
) 
1585         errln(UnicodeString("The offset for 10 AM, 6/1/98 (with a 1-hour DST offset) should have been -4 hours, but we got ") 
1586               + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1595 TimeZoneTest::TestAlternateRules() 
1597     // Like TestDSTSavings, this test should probably be integrated somehow with the main 
1598     // test at the top of this class, but I didn't have time to figure out how to do that. 
1601     SimpleTimeZone 
tz(-5 * U_MILLIS_PER_HOUR
, "alternateRuleTest"); 
1603     // test the day-of-month API 
1604     UErrorCode status 
= U_ZERO_ERROR
; 
1605     tz
.setStartRule(UCAL_MARCH
, 10, 12 * U_MILLIS_PER_HOUR
, status
); 
1606     if(U_FAILURE(status
)) 
1607         errln("tz.setStartRule failed"); 
1608     tz
.setEndRule(UCAL_OCTOBER
, 20, 12 * U_MILLIS_PER_HOUR
, status
); 
1609     if(U_FAILURE(status
)) 
1610         errln("tz.setStartRule failed"); 
1612     int32_t offset 
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_MARCH
, 5, 
1613                               UCAL_THURSDAY
, 10 * U_MILLIS_PER_HOUR
,status
); 
1614     if (offset 
!= -5 * U_MILLIS_PER_HOUR
) 
1615         errln(UnicodeString("The offset for 10AM, 3/5/98 should have been -5 hours, but we got ") 
1616               + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1618     offset 
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_MARCH
, 15, 
1619                           UCAL_SUNDAY
, 10 * millisPerHour
,status
); 
1620     if (offset 
!= -4 * U_MILLIS_PER_HOUR
) 
1621         errln(UnicodeString("The offset for 10AM, 3/15/98 should have been -4 hours, but we got ") 
1622               + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1624     offset 
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_OCTOBER
, 15, 
1625                           UCAL_THURSDAY
, 10 * millisPerHour
,status
); 
1626     if (offset 
!= -4 * U_MILLIS_PER_HOUR
) 
1627         errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ")              + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1629     offset 
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_OCTOBER
, 25, 
1630                           UCAL_SUNDAY
, 10 * millisPerHour
,status
); 
1631     if (offset 
!= -5 * U_MILLIS_PER_HOUR
) 
1632         errln(UnicodeString("The offset for 10AM, 10/25/98 should have been -5 hours, but we got ") 
1633               + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1635     // test the day-of-week-after-day-in-month API 
1636     tz
.setStartRule(UCAL_MARCH
, 10, UCAL_FRIDAY
, 12 * millisPerHour
, TRUE
, status
); 
1637     if(U_FAILURE(status
)) 
1638         errln("tz.setStartRule failed"); 
1639     tz
.setEndRule(UCAL_OCTOBER
, 20, UCAL_FRIDAY
, 12 * millisPerHour
, FALSE
, status
); 
1640     if(U_FAILURE(status
)) 
1641         errln("tz.setStartRule failed"); 
1643     offset 
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_MARCH
, 11, 
1644                           UCAL_WEDNESDAY
, 10 * millisPerHour
,status
); 
1645     if (offset 
!= -5 * U_MILLIS_PER_HOUR
) 
1646         errln(UnicodeString("The offset for 10AM, 3/11/98 should have been -5 hours, but we got ") 
1647               + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1649     offset 
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_MARCH
, 14, 
1650                           UCAL_SATURDAY
, 10 * millisPerHour
,status
); 
1651     if (offset 
!= -4 * U_MILLIS_PER_HOUR
) 
1652         errln(UnicodeString("The offset for 10AM, 3/14/98 should have been -4 hours, but we got ") 
1653               + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1655     offset 
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_OCTOBER
, 15, 
1656                           UCAL_THURSDAY
, 10 * millisPerHour
,status
); 
1657     if (offset 
!= -4 * U_MILLIS_PER_HOUR
) 
1658         errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ") 
1659               + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1661     offset 
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_OCTOBER
, 17, 
1662                           UCAL_SATURDAY
, 10 * millisPerHour
,status
); 
1663     if (offset 
!= -5 * U_MILLIS_PER_HOUR
) 
1664         errln(UnicodeString("The offset for 10AM, 10/17/98 should have been -5 hours, but we got ") 
1665               + (offset 
/ U_MILLIS_PER_HOUR
) + " hours."); 
1668 void TimeZoneTest::TestFractionalDST() { 
1669     const char* tzName 
= "Australia/Lord_Howe"; // 30 min offset 
1670     TimeZone
* tz_icu 
= TimeZone::createTimeZone(tzName
); 
1671         int dst_icu 
= tz_icu
->getDSTSavings(); 
1673     int32_t expected 
= 1800000; 
1674         if (expected 
!= dst_icu
) { 
1675             dataerrln(UnicodeString("java reports dst savings of ") + expected 
+ 
1676                 " but icu reports " + dst_icu 
+  
1677                 " for tz " + tz_icu
->getID(id
)); 
1679             logln(UnicodeString("both java and icu report dst savings of ") + expected 
+ " for tz " + tz_icu
->getID(id
)); 
1685  * Test country code support.  Jitterbug 776. 
1687 void TimeZoneTest::TestCountries() { 
1688     // Make sure America/Los_Angeles is in the "US" group, and 
1689     // Asia/Tokyo isn't.  Vice versa for the "JP" group. 
1690     UErrorCode ec 
= U_ZERO_ERROR
; 
1692     StringEnumeration
* s 
= TimeZone::createEnumeration("US"); 
1694         dataerrln("Unable to create TimeZone enumeration for US"); 
1698     UBool la 
= FALSE
, tokyo 
= FALSE
; 
1699     UnicodeString 
laZone("America/Los_Angeles", ""); 
1700     UnicodeString 
tokyoZone("Asia/Tokyo", ""); 
1703     if (s 
== NULL 
|| n 
<= 0) { 
1704         dataerrln("FAIL: TimeZone::createEnumeration() returned nothing"); 
1707     for (i
=0; i
<n
; ++i
) { 
1708         const UnicodeString
* id 
= s
->snext(ec
); 
1709         if (*id 
== (laZone
)) { 
1712         if (*id 
== (tokyoZone
)) { 
1717         errln("FAIL: " + laZone 
+ " in US = " + la
); 
1718         errln("FAIL: " + tokyoZone 
+ " in US = " + tokyo
); 
1722     s 
= TimeZone::createEnumeration("JP"); 
1724     la 
= FALSE
; tokyo 
= FALSE
; 
1726     for (i
=0; i
<n
; ++i
) { 
1727         const UnicodeString
* id 
= s
->snext(ec
); 
1728         if (*id 
== (laZone
)) { 
1731         if (*id 
== (tokyoZone
)) { 
1736         errln("FAIL: " + laZone 
+ " in JP = " + la
); 
1737         errln("FAIL: " + tokyoZone 
+ " in JP = " + tokyo
); 
1739     StringEnumeration
* s1 
= TimeZone::createEnumeration("US"); 
1740     StringEnumeration
* s2 
= TimeZone::createEnumeration("US"); 
1742         const UnicodeString
* id1 
= s1
->snext(ec
); 
1743         if(id1
==NULL 
|| U_FAILURE(ec
)){ 
1744             errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n
,i
); 
1746         TimeZone
* tz1 
= TimeZone::createTimeZone(*id1
); 
1747         for(int j
=0; j
<n
;++j
){ 
1748             const UnicodeString
* id2 
= s2
->snext(ec
); 
1749             if(id2
==NULL 
|| U_FAILURE(ec
)){ 
1750                 errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n
,i
); 
1752             TimeZone
* tz2 
= TimeZone::createTimeZone(*id2
); 
1753             if(tz1
->hasSameRules(*tz2
)){ 
1754                 logln("ID1 : " + *id1
+" == ID2 : " +*id2
); 
1765 void TimeZoneTest::TestHistorical() { 
1766     const int32_t H 
= U_MILLIS_PER_HOUR
; 
1769         int32_t time
; // epoch seconds 
1770         int32_t offset
; // total offset (millis) 
1772         // Add transition points (before/after) as desired to test historical 
1774         {"America/Los_Angeles", 638963999, -8*H
}, // Sun Apr 01 01:59:59 GMT-08:00 1990 
1775         {"America/Los_Angeles", 638964000, -7*H
}, // Sun Apr 01 03:00:00 GMT-07:00 1990 
1776         {"America/Los_Angeles", 657104399, -7*H
}, // Sun Oct 28 01:59:59 GMT-07:00 1990 
1777         {"America/Los_Angeles", 657104400, -8*H
}, // Sun Oct 28 01:00:00 GMT-08:00 1990 
1778         {"America/Goose_Bay", -116445601, -4*H
}, // Sun Apr 24 01:59:59 GMT-04:00 1966 
1779         {"America/Goose_Bay", -116445600, -3*H
}, // Sun Apr 24 03:00:00 GMT-03:00 1966 
1780         {"America/Goose_Bay", -100119601, -3*H
}, // Sun Oct 30 01:59:59 GMT-03:00 1966 
1781         {"America/Goose_Bay", -100119600, -4*H
}, // Sun Oct 30 01:00:00 GMT-04:00 1966 
1782         {"America/Goose_Bay", -84391201, -4*H
}, // Sun Apr 30 01:59:59 GMT-04:00 1967 
1783         {"America/Goose_Bay", -84391200, -3*H
}, // Sun Apr 30 03:00:00 GMT-03:00 1967 
1784         {"America/Goose_Bay", -68670001, -3*H
}, // Sun Oct 29 01:59:59 GMT-03:00 1967 
1785         {"America/Goose_Bay", -68670000, -4*H
}, // Sun Oct 29 01:00:00 GMT-04:00 1967 
1789     for (int32_t i
=0; DATA
[i
].id
!=0; ++i
) { 
1790         const char* id 
= DATA
[i
].id
; 
1791         TimeZone 
*tz 
= TimeZone::createTimeZone(id
); 
1794             errln("FAIL: Cannot create %s", id
); 
1795         } else if (tz
->getID(s
) != UnicodeString(id
)) { 
1796             dataerrln((UnicodeString
)"FAIL: createTimeZone(" + id 
+ ") => " + s
); 
1798             UErrorCode ec 
= U_ZERO_ERROR
; 
1800             UDate when 
= (double) DATA
[i
].time 
* U_MILLIS_PER_SECOND
; 
1801             tz
->getOffset(when
, FALSE
, raw
, dst
, ec
); 
1802             if (U_FAILURE(ec
)) { 
1803                 errln("FAIL: getOffset"); 
1804             } else if ((raw
+dst
) != DATA
[i
].offset
) { 
1805                 errln((UnicodeString
)"FAIL: " + DATA
[i
].id 
+ ".getOffset(" + 
1807                       dateToString(when
) + ") => " + 
1810                 logln((UnicodeString
)"Ok: " + DATA
[i
].id 
+ ".getOffset(" + 
1812                       dateToString(when
) + ") => " + 
1820 void TimeZoneTest::TestEquivalentIDs() { 
1821     int32_t n 
= TimeZone::countEquivalentIDs("PST"); 
1823         dataerrln((UnicodeString
)"FAIL: countEquivalentIDs(PST) = " + n
); 
1825         UBool sawLA 
= FALSE
; 
1826         for (int32_t i
=0; i
<n
; ++i
) { 
1827             UnicodeString id 
= TimeZone::getEquivalentID("PST", i
); 
1828             logln((UnicodeString
)"" + i 
+ " : " + id
); 
1829             if (id 
== UnicodeString("America/Los_Angeles")) { 
1834             errln("FAIL: America/Los_Angeles should be in the list"); 
1839 // Test that a transition at the end of February is handled correctly. 
1840 void TimeZoneTest::TestFebruary() { 
1841     UErrorCode status 
= U_ZERO_ERROR
; 
1843     // Time zone with daylight savings time from the first Sunday in November 
1844     // to the last Sunday in February. 
1845     // Similar to the new rule for Brazil (Sao Paulo) in tzdata2006n. 
1847     // Note: In tzdata2007h, the rule had changed, so no actual zones uses 
1848     // lastSun in Feb anymore. 
1849     SimpleTimeZone 
tz1(-3 * U_MILLIS_PER_HOUR
,          // raw offset: 3h before (west of) GMT 
1850                        UNICODE_STRING("nov-feb", 7), 
1851                        UCAL_NOVEMBER
, 1, UCAL_SUNDAY
,   // start: November, first, Sunday 
1852                        0,                               //        midnight wall time 
1853                        UCAL_FEBRUARY
, -1, UCAL_SUNDAY
,  // end:   February, last, Sunday 
1854                        0,                               //        midnight wall time 
1856     if (U_FAILURE(status
)) { 
1857         errln("Unable to create the SimpleTimeZone(nov-feb): %s", u_errorName(status
)); 
1861     // Now hardcode the same rules as for Brazil in tzdata 2006n, so that 
1862     // we cover the intended code even when in the future zoneinfo hardcodes 
1863     // these transition dates. 
1864     SimpleTimeZone 
tz2(-3 * U_MILLIS_PER_HOUR
,          // raw offset: 3h before (west of) GMT 
1865                        UNICODE_STRING("nov-feb2", 8), 
1866                        UCAL_NOVEMBER
, 1, -UCAL_SUNDAY
,  // start: November, 1 or after, Sunday 
1867                        0,                               //        midnight wall time 
1868                        UCAL_FEBRUARY
, -29, -UCAL_SUNDAY
,// end:   February, 29 or before, Sunday 
1869                        0,                               //        midnight wall time 
1871     if (U_FAILURE(status
)) { 
1872         errln("Unable to create the SimpleTimeZone(nov-feb2): %s", u_errorName(status
)); 
1876     // Gregorian calendar with the UTC time zone for getting sample test date/times. 
1877     GregorianCalendar 
gc(*TimeZone::getGMT(), status
); 
1878     if (U_FAILURE(status
)) { 
1879         dataerrln("Unable to create the UTC calendar: %s", u_errorName(status
)); 
1885         int32_t year
, month
, day
, hour
, minute
, second
; 
1886         // Expected time zone offset in hours after GMT (negative=before GMT). 
1887         int32_t offsetHours
; 
1889         { 2006, UCAL_NOVEMBER
,  5, 02, 59, 59, -3 }, 
1890         { 2006, UCAL_NOVEMBER
,  5, 03, 00, 00, -2 }, 
1891         { 2007, UCAL_FEBRUARY
, 25, 01, 59, 59, -2 }, 
1892         { 2007, UCAL_FEBRUARY
, 25, 02, 00, 00, -3 }, 
1894         { 2007, UCAL_NOVEMBER
,  4, 02, 59, 59, -3 }, 
1895         { 2007, UCAL_NOVEMBER
,  4, 03, 00, 00, -2 }, 
1896         { 2008, UCAL_FEBRUARY
, 24, 01, 59, 59, -2 }, 
1897         { 2008, UCAL_FEBRUARY
, 24, 02, 00, 00, -3 }, 
1899         { 2008, UCAL_NOVEMBER
,  2, 02, 59, 59, -3 }, 
1900         { 2008, UCAL_NOVEMBER
,  2, 03, 00, 00, -2 }, 
1901         { 2009, UCAL_FEBRUARY
, 22, 01, 59, 59, -2 }, 
1902         { 2009, UCAL_FEBRUARY
, 22, 02, 00, 00, -3 }, 
1904         { 2009, UCAL_NOVEMBER
,  1, 02, 59, 59, -3 }, 
1905         { 2009, UCAL_NOVEMBER
,  1, 03, 00, 00, -2 }, 
1906         { 2010, UCAL_FEBRUARY
, 28, 01, 59, 59, -2 }, 
1907         { 2010, UCAL_FEBRUARY
, 28, 02, 00, 00, -3 } 
1910     TimeZone 
*timezones
[] = { &tz1
, &tz2 
}; 
1914     int32_t t
, i
, raw
, dst
; 
1915     for (t 
= 0; t 
< UPRV_LENGTHOF(timezones
); ++t
) { 
1917         for (i 
= 0; i 
< UPRV_LENGTHOF(data
); ++i
) { 
1918             gc
.set(data
[i
].year
, data
[i
].month
, data
[i
].day
, 
1919                    data
[i
].hour
, data
[i
].minute
, data
[i
].second
); 
1920             dt 
= gc
.getTime(status
); 
1921             if (U_FAILURE(status
)) { 
1922                 errln("test case %d.%d: bad date/time %04d-%02d-%02d %02d:%02d:%02d", 
1924                       data
[i
].year
, data
[i
].month 
+ 1, data
[i
].day
, 
1925                       data
[i
].hour
, data
[i
].minute
, data
[i
].second
); 
1926                 status 
= U_ZERO_ERROR
; 
1929             tz
->getOffset(dt
, FALSE
, raw
, dst
, status
); 
1930             if (U_FAILURE(status
)) { 
1931                 errln("test case %d.%d: tz.getOffset(%04d-%02d-%02d %02d:%02d:%02d) fails: %s", 
1933                       data
[i
].year
, data
[i
].month 
+ 1, data
[i
].day
, 
1934                       data
[i
].hour
, data
[i
].minute
, data
[i
].second
, 
1935                       u_errorName(status
)); 
1936                 status 
= U_ZERO_ERROR
; 
1937             } else if ((raw 
+ dst
) != data
[i
].offsetHours 
* U_MILLIS_PER_HOUR
) { 
1938                 errln("test case %d.%d: tz.getOffset(%04d-%02d-%02d %02d:%02d:%02d) returns %d+%d != %d", 
1940                       data
[i
].year
, data
[i
].month 
+ 1, data
[i
].day
, 
1941                       data
[i
].hour
, data
[i
].minute
, data
[i
].second
, 
1942                       raw
, dst
, data
[i
].offsetHours 
* U_MILLIS_PER_HOUR
); 
1948 void TimeZoneTest::TestCanonicalIDAPI() { 
1949     // Bogus input string. 
1950     UnicodeString bogus
; 
1952     UnicodeString canonicalID
; 
1953     UErrorCode ec 
= U_ZERO_ERROR
; 
1954     UnicodeString 
*pResult 
= &TimeZone::getCanonicalID(bogus
, canonicalID
, ec
); 
1955     assertEquals("TimeZone::getCanonicalID(bogus) should fail", U_ILLEGAL_ARGUMENT_ERROR
, ec
); 
1956     assertTrue("TimeZone::getCanonicalID(bogus) should return the dest string", pResult 
== &canonicalID
); 
1958     // U_FAILURE on input. 
1959     UnicodeString 
berlin("Europe/Berlin"); 
1960     ec 
= U_MEMORY_ALLOCATION_ERROR
; 
1961     pResult 
= &TimeZone::getCanonicalID(berlin
, canonicalID
, ec
); 
1962     assertEquals("TimeZone::getCanonicalID(failure) should fail", U_MEMORY_ALLOCATION_ERROR
, ec
); 
1963     assertTrue("TimeZone::getCanonicalID(failure) should return the dest string", pResult 
== &canonicalID
); 
1965     // Valid input should un-bogus the dest string. 
1966     canonicalID
.setToBogus(); 
1968     pResult 
= &TimeZone::getCanonicalID(berlin
, canonicalID
, ec
); 
1969     assertSuccess("TimeZone::getCanonicalID(bogus dest) should succeed", ec
, TRUE
); 
1970     assertTrue("TimeZone::getCanonicalID(bogus dest) should return the dest string", pResult 
== &canonicalID
); 
1971     assertFalse("TimeZone::getCanonicalID(bogus dest) should un-bogus the dest string", canonicalID
.isBogus()); 
1972     assertEquals("TimeZone::getCanonicalID(bogus dest) unexpected result", canonicalID
, berlin
, TRUE
); 
1975 void TimeZoneTest::TestCanonicalID() { 
1977     // Some canonical IDs in CLDR are defined as "Link" 
1979     static const struct { 
1983         {"Africa/Addis_Ababa", "Africa/Nairobi"}, 
1984         {"Africa/Asmera", "Africa/Nairobi"}, 
1985         {"Africa/Bamako", "Africa/Abidjan"}, 
1986         {"Africa/Bangui", "Africa/Lagos"}, 
1987         {"Africa/Banjul", "Africa/Abidjan"}, 
1988         {"Africa/Blantyre", "Africa/Maputo"}, 
1989         {"Africa/Brazzaville", "Africa/Lagos"}, 
1990         {"Africa/Bujumbura", "Africa/Maputo"}, 
1991         {"Africa/Conakry", "Africa/Abidjan"}, 
1992         {"Africa/Dakar", "Africa/Abidjan"}, 
1993         {"Africa/Dar_es_Salaam", "Africa/Nairobi"}, 
1994         {"Africa/Djibouti", "Africa/Nairobi"}, 
1995         {"Africa/Douala", "Africa/Lagos"}, 
1996         {"Africa/Freetown", "Africa/Abidjan"}, 
1997         {"Africa/Gaborone", "Africa/Maputo"}, 
1998         {"Africa/Harare", "Africa/Maputo"}, 
1999         {"Africa/Kampala", "Africa/Nairobi"}, 
2000         {"Africa/Khartoum", "Africa/Juba"}, 
2001         {"Africa/Kigali", "Africa/Maputo"}, 
2002         {"Africa/Kinshasa", "Africa/Lagos"}, 
2003         {"Africa/Libreville", "Africa/Lagos"}, 
2004         {"Africa/Lome", "Africa/Abidjan"}, 
2005         {"Africa/Luanda", "Africa/Lagos"}, 
2006         {"Africa/Lubumbashi", "Africa/Maputo"}, 
2007         {"Africa/Lusaka", "Africa/Maputo"}, 
2008         {"Africa/Maseru", "Africa/Johannesburg"}, 
2009         {"Africa/Malabo", "Africa/Lagos"}, 
2010         {"Africa/Mbabane", "Africa/Johannesburg"}, 
2011         {"Africa/Mogadishu", "Africa/Nairobi"}, 
2012         {"Africa/Niamey", "Africa/Lagos"}, 
2013         {"Africa/Nouakchott", "Africa/Abidjan"}, 
2014         {"Africa/Ouagadougou", "Africa/Abidjan"}, 
2015         {"Africa/Porto-Novo", "Africa/Lagos"}, 
2016         {"Africa/Sao_Tome", "Africa/Abidjan"}, 
2017         {"America/Antigua", "America/Port_of_Spain"}, 
2018         {"America/Anguilla", "America/Port_of_Spain"}, 
2019         {"America/Curacao", "America/Aruba"}, 
2020         {"America/Dominica", "America/Port_of_Spain"}, 
2021         {"America/Grenada", "America/Port_of_Spain"}, 
2022         {"America/Guadeloupe", "America/Port_of_Spain"}, 
2023         {"America/Kralendijk", "America/Aruba"}, 
2024         {"America/Lower_Princes", "America/Aruba"}, 
2025         {"America/Marigot", "America/Port_of_Spain"}, 
2026         {"America/Montserrat", "America/Port_of_Spain"}, 
2027         {"America/Panama", "America/Cayman"}, 
2028         {"America/Shiprock", "America/Denver"}, 
2029         {"America/St_Barthelemy", "America/Port_of_Spain"}, 
2030         {"America/St_Kitts", "America/Port_of_Spain"}, 
2031         {"America/St_Lucia", "America/Port_of_Spain"}, 
2032         {"America/St_Thomas", "America/Port_of_Spain"}, 
2033         {"America/St_Vincent", "America/Port_of_Spain"}, 
2034         {"America/Toronto", "America/Montreal"}, 
2035         {"America/Tortola", "America/Port_of_Spain"}, 
2036         {"America/Virgin", "America/Port_of_Spain"}, 
2037         {"Antarctica/South_Pole", "Antarctica/McMurdo"}, 
2038         {"Arctic/Longyearbyen", "Europe/Oslo"}, 
2039         {"Asia/Kuwait", "Asia/Aden"}, 
2040         {"Asia/Muscat", "Asia/Dubai"}, 
2041         {"Asia/Phnom_Penh", "Asia/Bangkok"}, 
2042         {"Asia/Qatar", "Asia/Bahrain"}, 
2043         {"Asia/Riyadh", "Asia/Aden"}, 
2044         {"Asia/Vientiane", "Asia/Bangkok"}, 
2045         {"Atlantic/Jan_Mayen", "Europe/Oslo"}, 
2046         {"Atlantic/St_Helena", "Africa/Abidjan"}, 
2047         {"Europe/Bratislava", "Europe/Prague"}, 
2048         {"Europe/Busingen", "Europe/Zurich"}, 
2049         {"Europe/Guernsey", "Europe/London"}, 
2050         {"Europe/Isle_of_Man", "Europe/London"}, 
2051         {"Europe/Jersey", "Europe/London"}, 
2052         {"Europe/Ljubljana", "Europe/Belgrade"}, 
2053         {"Europe/Mariehamn", "Europe/Helsinki"}, 
2054         {"Europe/Podgorica", "Europe/Belgrade"}, 
2055         {"Europe/San_Marino", "Europe/Rome"}, 
2056         {"Europe/Sarajevo", "Europe/Belgrade"}, 
2057         {"Europe/Skopje", "Europe/Belgrade"}, 
2058         {"Europe/Vaduz", "Europe/Zurich"}, 
2059         {"Europe/Vatican", "Europe/Rome"}, 
2060         {"Europe/Zagreb", "Europe/Belgrade"}, 
2061         {"Indian/Antananarivo", "Africa/Nairobi"}, 
2062         {"Indian/Comoro", "Africa/Nairobi"}, 
2063         {"Indian/Mayotte", "Africa/Nairobi"}, 
2064         {"Pacific/Auckland", "Antarctica/McMurdo"}, 
2065         {"Pacific/Johnston", "Pacific/Honolulu"}, 
2066         {"Pacific/Midway", "Pacific/Pago_Pago"}, 
2067         {"Pacific/Saipan", "Pacific/Guam"}, 
2071     // Following IDs are aliases of Etc/GMT in CLDR, 
2072     // but Olson tzdata has 3 independent definitions 
2073     // for Etc/GMT, Etc/UTC, Etc/UCT. 
2074     // Until we merge them into one equivalent group 
2075     // in zoneinfo.res, we exclude them in the test 
2077     static const char* excluded2
[] = { 
2080         "Etc/Universal", "Universal", 
2081         "Etc/Zulu", "Zulu", 0 
2084     // Walk through equivalency groups 
2085     UErrorCode ec 
= U_ZERO_ERROR
; 
2086     int32_t s_length
, i
, j
, k
; 
2087     StringEnumeration
* s 
= TimeZone::createEnumeration(); 
2089         dataerrln("Unable to create TimeZone enumeration"); 
2092     UnicodeString canonicalID
, tmpCanonical
; 
2093     s_length 
= s
->count(ec
); 
2094     for (i 
= 0; i 
< s_length
;++i
) { 
2095         const UnicodeString 
*tzid 
= s
->snext(ec
); 
2096         int32_t nEquiv 
= TimeZone::countEquivalentIDs(*tzid
); 
2100         UBool bFoundCanonical 
= FALSE
; 
2101         // Make sure getCanonicalID returns the exact same result 
2102         // for all entries within a same equivalency group with some 
2103         // exceptions listed in exluded1. 
2104         // Also, one of them must be canonical id. 
2105         for (j 
= 0; j 
< nEquiv
; j
++) { 
2106             UnicodeString tmp 
= TimeZone::getEquivalentID(*tzid
, j
); 
2107             TimeZone::getCanonicalID(tmp
, tmpCanonical
, ec
); 
2108             if (U_FAILURE(ec
)) { 
2109                 errln((UnicodeString
)"FAIL: getCanonicalID(" + tmp 
+ ") failed."); 
2113             // Some exceptional cases 
2114             for (k 
= 0; excluded1
[k
].alias 
!= 0; k
++) { 
2115                 if (tmpCanonical 
== excluded1
[k
].alias
) { 
2116                     tmpCanonical 
= excluded1
[k
].zone
; 
2121                 canonicalID 
= tmpCanonical
; 
2122             } else if (canonicalID 
!= tmpCanonical
) { 
2123                 errln("FAIL: getCanonicalID(" + tmp 
+ ") returned " + tmpCanonical 
+ " expected:" + canonicalID
); 
2126             if (canonicalID 
== tmp
) { 
2127                 bFoundCanonical 
= TRUE
; 
2130         // At least one ID in an equvalency group must match the 
2132         if (bFoundCanonical 
== FALSE
) { 
2133             // test exclusion because of differences between Olson tzdata and CLDR 
2134             UBool isExcluded 
= FALSE
; 
2135             for (k 
= 0; excluded2
[k
] != 0; k
++) { 
2136                 if (*tzid 
== UnicodeString(excluded2
[k
])) { 
2144             errln((UnicodeString
)"FAIL: No timezone ids match the canonical ID " + canonicalID
); 
2149     // Testing some special cases 
2150     static const struct { 
2152         const char *expected
; 
2155         {"GMT-03", "GMT-03:00", FALSE
}, 
2156         {"GMT+4", "GMT+04:00", FALSE
}, 
2157         {"GMT-055", "GMT-00:55", FALSE
}, 
2158         {"GMT+430", "GMT+04:30", FALSE
}, 
2159         {"GMT-12:15", "GMT-12:15", FALSE
}, 
2160         {"GMT-091015", "GMT-09:10:15", FALSE
}, 
2161         {"GMT+1:90", 0, FALSE
}, 
2162         {"America/Argentina/Buenos_Aires", "America/Buenos_Aires", TRUE
}, 
2163         {"Etc/Unknown", "Etc/Unknown", FALSE
}, 
2164         {"bogus", 0, FALSE
}, 
2166         {"America/Marigot", "America/Marigot", TRUE
},     // Olson link, but CLDR canonical (#8953) 
2167         {"Europe/Bratislava", "Europe/Bratislava", TRUE
}, // Same as above 
2172     for (i 
= 0; data
[i
].id 
!= 0; i
++) { 
2173         TimeZone::getCanonicalID(UnicodeString(data
[i
].id
), canonicalID
, isSystemID
, ec
); 
2174         if (U_FAILURE(ec
)) { 
2175             if (ec 
!= U_ILLEGAL_ARGUMENT_ERROR 
|| data
[i
].expected 
!= 0) { 
2176                 errln((UnicodeString
)"FAIL: getCanonicalID(\"" + data
[i
].id
 
2177                     + "\") returned status U_ILLEGAL_ARGUMENT_ERROR"); 
2182         if (canonicalID 
!= data
[i
].expected
) { 
2183             dataerrln((UnicodeString
)"FAIL: getCanonicalID(\"" + data
[i
].id
 
2184                 + "\") returned " + canonicalID 
+ " - expected: " + data
[i
].expected
); 
2186         if (isSystemID 
!= data
[i
].isSystem
) { 
2187             dataerrln((UnicodeString
)"FAIL: getCanonicalID(\"" + data
[i
].id
 
2188                 + "\") set " + isSystemID 
+ " to isSystemID"); 
2194 //  Test Display Names, choosing zones and lcoales where there are multiple 
2195 //                      meta-zones defined. 
2198     const char            *zoneName
; 
2199     const char            *localeName
; 
2201     TimeZone::EDisplayType style
; 
2202     const char            *expectedDisplayName
; }  
2203  zoneDisplayTestData 
[] =  { 
2204      //  zone id         locale   summer   format          expected display name 
2205       {"Europe/London",     "en", FALSE
, TimeZone::SHORT
, "GMT"}, 
2206       {"Europe/London",     "en", FALSE
, TimeZone::LONG
,  "Greenwich Mean Time"}, 
2207       {"Europe/London",     "en", TRUE
,  TimeZone::SHORT
, "GMT+1" /*"BST"*/}, 
2208       {"Europe/London",     "en", TRUE
,  TimeZone::LONG
,  "British Summer Time"}, 
2210       {"America/Anchorage", "en", FALSE
, TimeZone::SHORT
, "AKST"}, 
2211       {"America/Anchorage", "en", FALSE
, TimeZone::LONG
,  "Alaska Standard Time"}, 
2212       {"America/Anchorage", "en", TRUE
,  TimeZone::SHORT
, "AKDT"}, 
2213       {"America/Anchorage", "en", TRUE
,  TimeZone::LONG
,  "Alaska Daylight Time"}, 
2215       // Southern Hemisphere, all data from meta:Australia_Western 
2216       {"Australia/Perth",   "en", FALSE
, TimeZone::SHORT
, "GMT+8"/*"AWST"*/}, 
2217       {"Australia/Perth",   "en", FALSE
, TimeZone::LONG
,  "Australian Western Standard Time"}, 
2218       // Note: Perth does not observe DST currently. When display name is missing, 
2219       // the localized GMT format with the current offset is used even daylight name was 
2220       // requested. See #9350. 
2221       {"Australia/Perth",   "en", TRUE
,  TimeZone::SHORT
, "GMT+8"/*"AWDT"*/}, 
2222       {"Australia/Perth",   "en", TRUE
,  TimeZone::LONG
,  "Australian Western Daylight Time"}, 
2224       {"America/Sao_Paulo",  "en", FALSE
, TimeZone::SHORT
, "GMT-3"/*"BRT"*/}, 
2225       {"America/Sao_Paulo",  "en", FALSE
, TimeZone::LONG
,  "Brasilia Standard Time"}, 
2226       {"America/Sao_Paulo",  "en", TRUE
,  TimeZone::SHORT
, "GMT-2"/*"BRST"*/}, 
2227       {"America/Sao_Paulo",  "en", TRUE
,  TimeZone::LONG
,  "Brasilia Summer Time"}, 
2229       // No Summer Time, but had it before 1983. 
2230       {"Pacific/Honolulu",   "en", FALSE
, TimeZone::SHORT
, "HST"}, 
2231       {"Pacific/Honolulu",   "en", FALSE
, TimeZone::LONG
,  "Hawaii-Aleutian Standard Time"}, 
2232       {"Pacific/Honolulu",   "en", TRUE
,  TimeZone::SHORT
, "HDT"}, 
2233       {"Pacific/Honolulu",   "en", TRUE
,  TimeZone::LONG
,  "Hawaii-Aleutian Daylight Time"}, 
2235       // Northern, has Summer, not commonly used. 
2236       {"Europe/Helsinki",    "en", FALSE
, TimeZone::SHORT
, "GMT+2"/*"EET"*/}, 
2237       {"Europe/Helsinki",    "en", FALSE
, TimeZone::LONG
,  "Eastern European Standard Time"}, 
2238       {"Europe/Helsinki",    "en", TRUE
,  TimeZone::SHORT
, "GMT+3"/*"EEST"*/}, 
2239       {"Europe/Helsinki",    "en", TRUE
,  TimeZone::LONG
,  "Eastern European Summer Time"}, 
2241       // Repeating the test data for DST.  The test data below trigger the problem reported 
2243       {"Europe/London",       "en", TRUE
, TimeZone::SHORT
, "GMT+1" /*"BST"*/}, 
2244       {"Europe/London",       "en", TRUE
, TimeZone::LONG
,  "British Summer Time"}, 
2246       {NULL
, NULL
, FALSE
, TimeZone::SHORT
, NULL
}   // NULL values terminate list 
2249 void TimeZoneTest::TestDisplayNamesMeta() { 
2250     UErrorCode status 
= U_ZERO_ERROR
; 
2251     GregorianCalendar 
cal(*TimeZone::getGMT(), status
); 
2252     if (failure(status
, "GregorianCalendar", TRUE
)) return; 
2254     UBool sawAnError 
= FALSE
; 
2255     for (int testNum   
= 0; zoneDisplayTestData
[testNum
].zoneName 
!= NULL
; testNum
++) { 
2256         Locale locale  
= Locale::createFromName(zoneDisplayTestData
[testNum
].localeName
); 
2257         TimeZone 
*zone 
= TimeZone::createTimeZone(zoneDisplayTestData
[testNum
].zoneName
); 
2258         UnicodeString displayName
; 
2259         zone
->getDisplayName(zoneDisplayTestData
[testNum
].summerTime
, 
2260                              zoneDisplayTestData
[testNum
].style
, 
2263         if (displayName 
!= zoneDisplayTestData
[testNum
].expectedDisplayName
) { 
2265             UErrorCode status 
= U_ZERO_ERROR
; 
2266             displayName
.extract(name
, 100, NULL
, status
); 
2267             if (isDevelopmentBuild
) { 
2269                 dataerrln("Incorrect time zone display name.  zone = \"%s\",\n" 
2270                       "   locale = \"%s\",   style = %s,  Summertime = %d\n" 
2271                       "   Expected \"%s\", " 
2272                       "   Got \"%s\"\n   Error: %s", zoneDisplayTestData
[testNum
].zoneName
, 
2273                                          zoneDisplayTestData
[testNum
].localeName
, 
2274                                          zoneDisplayTestData
[testNum
].style
==TimeZone::SHORT 
? 
2276                                          zoneDisplayTestData
[testNum
].summerTime
, 
2277                                          zoneDisplayTestData
[testNum
].expectedDisplayName
, 
2279                                          u_errorName(status
)); 
2281                 logln("Incorrect time zone display name.  zone = \"%s\",\n" 
2282                       "   locale = \"%s\",   style = %s,  Summertime = %d\n" 
2283                       "   Expected \"%s\", " 
2284                       "   Got \"%s\"\n", zoneDisplayTestData
[testNum
].zoneName
, 
2285                                          zoneDisplayTestData
[testNum
].localeName
, 
2286                                          zoneDisplayTestData
[testNum
].style
==TimeZone::SHORT 
? 
2288                                          zoneDisplayTestData
[testNum
].summerTime
, 
2289                                          zoneDisplayTestData
[testNum
].expectedDisplayName
, 
2296         dataerrln("***Note: Errors could be the result of changes to zoneStrings locale data"); 
2300 void TimeZoneTest::TestGetRegion() 
2302     static const struct { 
2306         {"America/Los_Angeles",             "US"}, 
2307         {"America/Indianapolis",            "US"},  // CLDR canonical, Olson backward 
2308         {"America/Indiana/Indianapolis",    "US"},  // CLDR alias 
2309         {"Mexico/General",                  "MX"},  // Link America/Mexico_City, Olson backward 
2312         {"PST",                             "US"},  // Link America/Los_Angeles 
2313         {"Europe/Helsinki",                 "FI"}, 
2314         {"Europe/Mariehamn",                "AX"},  // Link Europe/Helsinki, but in zone.tab 
2315         {"Asia/Riyadh",                     "SA"}, 
2316         // tz file solar87 was removed from tzdata2013i 
2317         // {"Asia/Riyadh87",                   "001"}, // this should be "SA" actually, but not in zone.tab 
2318         {"Etc/Unknown",                     0},  // CLDR canonical, but not a sysmte zone ID 
2319         {"bogus",                           0},  // bogus 
2320         {"GMT+08:00",                       0},  // a custom ID, not a system zone ID 
2327     for (i 
= 0; data
[i
].id
; i
++) { 
2329         TimeZone::getRegion(data
[i
].id
, region
, sizeof(region
), sts
); 
2330         if (U_SUCCESS(sts
)) { 
2331             if (data
[i
].region 
== 0) { 
2332                 errln((UnicodeString
)"Fail: getRegion(\"" + data
[i
].id 
+ "\") returns " 
2333                     + region 
+ " [expected: U_ILLEGAL_ARGUMENT_ERROR]"); 
2334             } else if (uprv_strcmp(region
, data
[i
].region
) != 0) { 
2335                 errln((UnicodeString
)"Fail: getRegion(\"" + data
[i
].id 
+ "\") returns " 
2336                     + region 
+ " [expected: " + data
[i
].region 
+ "]"); 
2338         } else if (sts 
== U_ILLEGAL_ARGUMENT_ERROR
) { 
2339             if (data
[i
].region 
!= 0) { 
2340                 dataerrln((UnicodeString
)"Fail: getRegion(\"" + data
[i
].id
 
2341                     + "\") returns error status U_ILLEGAL_ARGUMENT_ERROR [expected: " 
2342                     + data
[i
].region 
+ "]"); 
2345                 errln((UnicodeString
)"Fail: getRegion(\"" + data
[i
].id
 
2346                     + "\") returns an unexpected error status"); 
2350     // Extra test cases for short buffer 
2355     len 
= TimeZone::getRegion("America/New_York", region2
, sizeof(region2
), sts
); 
2356     if (sts 
== U_ILLEGAL_ARGUMENT_ERROR
) { 
2357         dataerrln("Error calling TimeZone::getRegion"); 
2359         if (sts 
!= U_STRING_NOT_TERMINATED_WARNING
) { 
2360             errln("Expected U_STRING_NOT_TERMINATED_WARNING"); 
2362         if (len 
!= 2) { // length of "US" 
2363             errln("Incorrect result length"); 
2365         if (uprv_strncmp(region2
, "US", 2) != 0) { 
2366             errln("Incorrect result"); 
2373     len 
= TimeZone::getRegion("America/Chicago", region1
, sizeof(region1
), sts
); 
2374     if (sts 
== U_ILLEGAL_ARGUMENT_ERROR
) { 
2375         dataerrln("Error calling TimeZone::getRegion"); 
2377         if (sts 
!= U_BUFFER_OVERFLOW_ERROR
) { 
2378             errln("Expected U_BUFFER_OVERFLOW_ERROR"); 
2380         if (len 
!= 2) { // length of "US" 
2381             errln("Incorrect result length"); 
2386 void TimeZoneTest::TestGetUnknown() { 
2387     const TimeZone 
&unknown 
= TimeZone::getUnknown(); 
2388     UnicodeString expectedID 
= UNICODE_STRING_SIMPLE("Etc/Unknown"); 
2390     assertEquals("getUnknown() wrong ID", expectedID
, unknown
.getID(id
)); 
2391     assertTrue("getUnknown() wrong offset", 0 == unknown
.getRawOffset()); 
2392     assertFalse("getUnknown() uses DST", unknown
.useDaylightTime()); 
2395 void TimeZoneTest::TestGetWindowsID(void) { 
2396     static const struct { 
2400         {"America/New_York",        "Eastern Standard Time"}, 
2401         {"America/Montreal",        "Eastern Standard Time"}, 
2402         {"America/Los_Angeles",     "Pacific Standard Time"}, 
2403         {"America/Vancouver",       "Pacific Standard Time"}, 
2404         {"Asia/Shanghai",           "China Standard Time"}, 
2405         {"Asia/Chongqing",          "China Standard Time"}, 
2406         {"America/Indianapolis",    "US Eastern Standard Time"},            // CLDR canonical name 
2407         {"America/Indiana/Indianapolis",    "US Eastern Standard Time"},    // tzdb canonical name 
2408         {"Asia/Khandyga",           "Yakutsk Standard Time"}, 
2409         {"Australia/Eucla",         ""}, // No Windows ID mapping 
2414     for (int32_t i 
= 0; TESTDATA
[i
].id 
!= 0; i
++) { 
2415         UErrorCode sts 
= U_ZERO_ERROR
; 
2416         UnicodeString windowsID
; 
2418         TimeZone::getWindowsID(UnicodeString(TESTDATA
[i
].id
), windowsID
, sts
); 
2419         assertSuccess(TESTDATA
[i
].id
, sts
); 
2420         assertEquals(TESTDATA
[i
].id
, UnicodeString(TESTDATA
[i
].winid
), windowsID
, TRUE
); 
2424 void TimeZoneTest::TestGetIDForWindowsID(void) { 
2425     static const struct { 
2430         {"Eastern Standard Time",   0,      "America/New_York"}, 
2431         {"Eastern Standard Time",   "US",   "America/New_York"}, 
2432         {"Eastern Standard Time",   "CA",   "America/Toronto"}, 
2433         {"Eastern Standard Time",   "CN",   "America/New_York"}, 
2434         {"China Standard Time",     0,      "Asia/Shanghai"}, 
2435         {"China Standard Time",     "CN",   "Asia/Shanghai"}, 
2436         {"China Standard Time",     "HK",   "Asia/Hong_Kong"}, 
2437         {"Mid-Atlantic Standard Time",  0,  ""}, // No tz database mapping 
2442     for (int32_t i 
= 0; TESTDATA
[i
].winid 
!= 0; i
++) { 
2443         UErrorCode sts 
= U_ZERO_ERROR
; 
2446         TimeZone::getIDForWindowsID(UnicodeString(TESTDATA
[i
].winid
), TESTDATA
[i
].region
, 
2448         assertSuccess(UnicodeString(TESTDATA
[i
].winid
) + "/" + TESTDATA
[i
].region
, sts
); 
2449         assertEquals(UnicodeString(TESTDATA
[i
].winid
) + "/" + TESTDATA
[i
].region
, TESTDATA
[i
].id
, id
, TRUE
); 
2453 #endif /* #if !UCONFIG_NO_FORMATTING */