1 /*********************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 1997-2013, International Business Machines Corporation 4 * and others. All Rights Reserved. 5 ***********************************************************************/ 6 7 #include "unicode/utypes.h" 8 9 #if !UCONFIG_NO_FORMATTING 10 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" 18 #include "tztest.h" 19 #include "cmemory.h" 20 #include "putilimp.h" 21 #include "cstring.h" 22 #include "olsontz.h" 23 24 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) 25 26 #define CASE(id,test) case id: \ 27 name = #test; \ 28 if (exec) { \ 29 logln(#test "---"); logln(""); \ 30 test(); \ 31 } \ 32 break 33 34 // ***************************************************************************** 35 // class TimeZoneTest 36 // ***************************************************************************** 37 38 // Some test case data is current date/tzdata version sensitive and producing errors 39 // when year/rule are changed. Although we want to keep our eyes on test failures 40 // caused by tzdata changes while development, keep maintaining test data in maintenance 41 // stream is a little bit hassle. ICU 49 or later versions are using minor version field 42 // to indicate a development build (0) or official release build (others). For development 43 // builds, a test failure triggers an error, while release builds only report them in 44 // verbose mode with logln. 45 static UBool isDevelopmentBuild = (U_ICU_VERSION_MINOR_NUM == 0); 46 47 void TimeZoneTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) 48 { 49 if (exec) { 50 logln("TestSuite TestTimeZone"); 51 } 52 TESTCASE_AUTO_BEGIN; 53 TESTCASE_AUTO(TestPRTOffset); 54 TESTCASE_AUTO(TestVariousAPI518); 55 TESTCASE_AUTO(TestGetAvailableIDs913); 56 TESTCASE_AUTO(TestGenericAPI); 57 TESTCASE_AUTO(TestRuleAPI); 58 TESTCASE_AUTO(TestShortZoneIDs); 59 TESTCASE_AUTO(TestCustomParse); 60 TESTCASE_AUTO(TestDisplayName); 61 TESTCASE_AUTO(TestDSTSavings); 62 TESTCASE_AUTO(TestAlternateRules); 63 TESTCASE_AUTO(TestCountries); 64 TESTCASE_AUTO(TestHistorical); 65 TESTCASE_AUTO(TestEquivalentIDs); 66 TESTCASE_AUTO(TestAliasedNames); 67 TESTCASE_AUTO(TestFractionalDST); 68 TESTCASE_AUTO(TestFebruary); 69 TESTCASE_AUTO(TestCanonicalID); 70 TESTCASE_AUTO(TestDisplayNamesMeta); 71 TESTCASE_AUTO(TestGetRegion); 72 TESTCASE_AUTO(TestGetAvailableIDsNew); 73 TESTCASE_AUTO(TestGetUnknown); 74 TESTCASE_AUTO_END; 75 } 76 77 const int32_t TimeZoneTest::millisPerHour = 3600000; 78 79 // --------------------------------------------------------------------------------- 80 81 /** 82 * Generic API testing for API coverage. 83 */ 84 void 85 TimeZoneTest::TestGenericAPI() 86 { 87 UnicodeString id("NewGMT"); 88 int32_t offset = 12345; 89 90 SimpleTimeZone *zone = new SimpleTimeZone(offset, id); 91 if (zone->useDaylightTime()) errln("FAIL: useDaylightTime should return FALSE"); 92 93 TimeZone* zoneclone = zone->clone(); 94 if (!(*zoneclone == *zone)) errln("FAIL: clone or operator== failed"); 95 zoneclone->setID("abc"); 96 if (!(*zoneclone != *zone)) errln("FAIL: clone or operator!= failed"); 97 delete zoneclone; 98 99 zoneclone = zone->clone(); 100 if (!(*zoneclone == *zone)) errln("FAIL: clone or operator== failed"); 101 zoneclone->setRawOffset(45678); 102 if (!(*zoneclone != *zone)) errln("FAIL: clone or operator!= failed"); 103 104 SimpleTimeZone copy(*zone); 105 if (!(copy == *zone)) errln("FAIL: copy constructor or operator== failed"); 106 copy = *(SimpleTimeZone*)zoneclone; 107 if (!(copy == *zoneclone)) errln("FAIL: assignment operator or operator== failed"); 108 109 TimeZone* saveDefault = TimeZone::createDefault(); 110 logln((UnicodeString)"TimeZone::createDefault() => " + saveDefault->getID(id)); 111 TimeZone* pstZone = TimeZone::createTimeZone("America/Los_Angeles"); 112 113 logln("call uprv_timezone() which uses the host"); 114 logln("to get the difference in seconds between coordinated universal"); 115 logln("time and local time. E.g., -28,800 for PST (GMT-8hrs)"); 116 117 int32_t tzoffset = uprv_timezone(); 118 logln(UnicodeString("Value returned from uprv_timezone = ") + tzoffset); 119 // Invert sign because UNIX semantics are backwards 120 if (tzoffset < 0) 121 tzoffset = -tzoffset; 122 if ((*saveDefault == *pstZone) && (tzoffset != 28800)) { 123 errln("FAIL: t_timezone may be incorrect. It is not 28800"); 124 } 125 126 if ((tzoffset % 900) != 0) { 127 /* 128 * Ticket#6364 and #7648 129 * A few time zones are using GMT offests not a multiple of 15 minutes. 130 * Therefore, we should not interpret such case as an error. 131 * We downgrade this from errln to infoln. When we see this message, 132 * we should examine if it is ignorable or not. 133 */ 134 infoln("WARNING: t_timezone may be incorrect. It is not a multiple of 15min.", tzoffset); 135 } 136 137 TimeZone::adoptDefault(zone); 138 TimeZone* defaultzone = TimeZone::createDefault(); 139 if (defaultzone == zone || 140 !(*defaultzone == *zone)) 141 errln("FAIL: createDefault failed"); 142 TimeZone::adoptDefault(saveDefault); 143 delete defaultzone; 144 delete zoneclone; 145 delete pstZone; 146 147 UErrorCode status = U_ZERO_ERROR; 148 const char* tzver = TimeZone::getTZDataVersion(status); 149 if (U_FAILURE(status)) { 150 errcheckln(status, "FAIL: getTZDataVersion failed - %s", u_errorName(status)); 151 } else if (uprv_strlen(tzver) != 5 /* 4 digits + 1 letter */) { 152 errln((UnicodeString)"FAIL: getTZDataVersion returned " + tzver); 153 } else { 154 logln((UnicodeString)"tzdata version: " + tzver); 155 } 156 } 157 158 // --------------------------------------------------------------------------------- 159 160 /** 161 * Test the setStartRule/setEndRule API calls. 162 */ 163 void 164 TimeZoneTest::TestRuleAPI() 165 { 166 UErrorCode status = U_ZERO_ERROR; 167 168 UDate offset = 60*60*1000*1.75; // Pick a weird offset 169 SimpleTimeZone *zone = new SimpleTimeZone((int32_t)offset, "TestZone"); 170 if (zone->useDaylightTime()) errln("FAIL: useDaylightTime should return FALSE"); 171 172 // Establish our expected transition times. Do this with a non-DST 173 // calendar with the (above) declared local offset. 174 GregorianCalendar *gc = new GregorianCalendar(*zone, status); 175 if (failure(status, "new GregorianCalendar", TRUE)) return; 176 gc->clear(); 177 gc->set(1990, UCAL_MARCH, 1); 178 UDate marchOneStd = gc->getTime(status); // Local Std time midnight 179 gc->clear(); 180 gc->set(1990, UCAL_JULY, 1); 181 UDate julyOneStd = gc->getTime(status); // Local Std time midnight 182 if (failure(status, "GregorianCalendar::getTime")) return; 183 184 // Starting and ending hours, WALL TIME 185 int32_t startHour = (int32_t)(2.25 * 3600000); 186 int32_t endHour = (int32_t)(3.5 * 3600000); 187 188 zone->setStartRule(UCAL_MARCH, 1, 0, startHour, status); 189 zone->setEndRule (UCAL_JULY, 1, 0, endHour, status); 190 191 delete gc; 192 gc = new GregorianCalendar(*zone, status); 193 if (failure(status, "new GregorianCalendar")) return; 194 195 UDate marchOne = marchOneStd + startHour; 196 UDate julyOne = julyOneStd + endHour - 3600000; // Adjust from wall to Std time 197 198 UDate expMarchOne = 636251400000.0; 199 if (marchOne != expMarchOne) 200 { 201 errln((UnicodeString)"FAIL: Expected start computed as " + marchOne + 202 " = " + dateToString(marchOne)); 203 logln((UnicodeString)" Should be " + expMarchOne + 204 " = " + dateToString(expMarchOne)); 205 } 206 207 UDate expJulyOne = 646793100000.0; 208 if (julyOne != expJulyOne) 209 { 210 errln((UnicodeString)"FAIL: Expected start computed as " + julyOne + 211 " = " + dateToString(julyOne)); 212 logln((UnicodeString)" Should be " + expJulyOne + 213 " = " + dateToString(expJulyOne)); 214 } 215 216 testUsingBinarySearch(*zone, date(90, UCAL_JANUARY, 1), date(90, UCAL_JUNE, 15), marchOne); 217 testUsingBinarySearch(*zone, date(90, UCAL_JUNE, 1), date(90, UCAL_DECEMBER, 31), julyOne); 218 219 if (zone->inDaylightTime(marchOne - 1000, status) || 220 !zone->inDaylightTime(marchOne, status)) 221 errln("FAIL: Start rule broken"); 222 if (!zone->inDaylightTime(julyOne - 1000, status) || 223 zone->inDaylightTime(julyOne, status)) 224 errln("FAIL: End rule broken"); 225 226 zone->setStartYear(1991); 227 if (zone->inDaylightTime(marchOne, status) || 228 zone->inDaylightTime(julyOne - 1000, status)) 229 errln("FAIL: Start year broken"); 230 231 failure(status, "TestRuleAPI"); 232 delete gc; 233 delete zone; 234 } 235 236 void 237 TimeZoneTest::findTransition(const TimeZone& tz, 238 UDate min, UDate max) { 239 UErrorCode ec = U_ZERO_ERROR; 240 UnicodeString id,s; 241 UBool startsInDST = tz.inDaylightTime(min, ec); 242 if (failure(ec, "TimeZone::inDaylightTime")) return; 243 if (tz.inDaylightTime(max, ec) == startsInDST) { 244 logln("Error: " + tz.getID(id) + ".inDaylightTime(" + dateToString(min) + ") = " + (startsInDST?"TRUE":"FALSE") + 245 ", inDaylightTime(" + dateToString(max) + ") = " + (startsInDST?"TRUE":"FALSE")); 246 return; 247 } 248 if (failure(ec, "TimeZone::inDaylightTime")) return; 249 while ((max - min) > INTERVAL) { 250 UDate mid = (min + max) / 2; 251 if (tz.inDaylightTime(mid, ec) == startsInDST) { 252 min = mid; 253 } else { 254 max = mid; 255 } 256 if (failure(ec, "TimeZone::inDaylightTime")) return; 257 } 258 min = 1000.0 * uprv_floor(min/1000.0); 259 max = 1000.0 * uprv_floor(max/1000.0); 260 logln(tz.getID(id) + " Before: " + min/1000 + " = " + 261 dateToString(min,s,tz)); 262 logln(tz.getID(id) + " After: " + max/1000 + " = " + 263 dateToString(max,s,tz)); 264 } 265 266 void 267 TimeZoneTest::testUsingBinarySearch(const TimeZone& tz, 268 UDate min, UDate max, 269 UDate expectedBoundary) 270 { 271 UErrorCode status = U_ZERO_ERROR; 272 UBool startsInDST = tz.inDaylightTime(min, status); 273 if (failure(status, "TimeZone::inDaylightTime")) return; 274 if (tz.inDaylightTime(max, status) == startsInDST) { 275 logln("Error: inDaylightTime(" + dateToString(max) + ") != " + ((!startsInDST)?"TRUE":"FALSE")); 276 return; 277 } 278 if (failure(status, "TimeZone::inDaylightTime")) return; 279 while ((max - min) > INTERVAL) { 280 UDate mid = (min + max) / 2; 281 if (tz.inDaylightTime(mid, status) == startsInDST) { 282 min = mid; 283 } else { 284 max = mid; 285 } 286 if (failure(status, "TimeZone::inDaylightTime")) return; 287 } 288 logln(UnicodeString("Binary Search Before: ") + uprv_floor(0.5 + min) + " = " + dateToString(min)); 289 logln(UnicodeString("Binary Search After: ") + uprv_floor(0.5 + max) + " = " + dateToString(max)); 290 UDate mindelta = expectedBoundary - min; 291 UDate maxdelta = max - expectedBoundary; 292 if (mindelta >= 0 && 293 mindelta <= INTERVAL && 294 maxdelta >= 0 && 295 maxdelta <= INTERVAL) 296 logln(UnicodeString("PASS: Expected bdry: ") + expectedBoundary + " = " + dateToString(expectedBoundary)); 297 else 298 errln(UnicodeString("FAIL: Expected bdry: ") + expectedBoundary + " = " + dateToString(expectedBoundary)); 299 } 300 301 const UDate TimeZoneTest::INTERVAL = 100; 302 303 // --------------------------------------------------------------------------------- 304 305 // ------------------------------------- 306 307 /** 308 * Test the offset of the PRT timezone. 309 */ 310 void 311 TimeZoneTest::TestPRTOffset() 312 { 313 TimeZone* tz = TimeZone::createTimeZone("PRT"); 314 if (tz == 0) { 315 errln("FAIL: TimeZone(PRT) is null"); 316 } 317 else { 318 int32_t expectedHour = -4; 319 double expectedOffset = (((double)expectedHour) * millisPerHour); 320 double foundOffset = tz->getRawOffset(); 321 int32_t foundHour = (int32_t)foundOffset / millisPerHour; 322 if (expectedOffset != foundOffset) { 323 dataerrln("FAIL: Offset for PRT should be %d, found %d", expectedHour, foundHour); 324 } else { 325 logln("PASS: Offset for PRT should be %d, found %d", expectedHour, foundHour); 326 } 327 } 328 delete tz; 329 } 330 331 // ------------------------------------- 332 333 /** 334 * Regress a specific bug with a sequence of API calls. 335 */ 336 void 337 TimeZoneTest::TestVariousAPI518() 338 { 339 UErrorCode status = U_ZERO_ERROR; 340 TimeZone* time_zone = TimeZone::createTimeZone("PST"); 341 UDate d = date(97, UCAL_APRIL, 30); 342 UnicodeString str; 343 logln("The timezone is " + time_zone->getID(str)); 344 if (!time_zone->inDaylightTime(d, status)) dataerrln("FAIL: inDaylightTime returned FALSE"); 345 if (failure(status, "TimeZone::inDaylightTime", TRUE)) return; 346 if (!time_zone->useDaylightTime()) dataerrln("FAIL: useDaylightTime returned FALSE"); 347 if (time_zone->getRawOffset() != - 8 * millisPerHour) dataerrln("FAIL: getRawOffset returned wrong value"); 348 GregorianCalendar *gc = new GregorianCalendar(status); 349 if (U_FAILURE(status)) { errln("FAIL: Couldn't create GregorianCalendar"); return; } 350 gc->setTime(d, status); 351 if (U_FAILURE(status)) { errln("FAIL: GregorianCalendar::setTime failed"); return; } 352 if (time_zone->getOffset(gc->AD, gc->get(UCAL_YEAR, status), gc->get(UCAL_MONTH, status), 353 gc->get(UCAL_DATE, status), (uint8_t)gc->get(UCAL_DAY_OF_WEEK, status), 0, status) != - 7 * millisPerHour) 354 dataerrln("FAIL: getOffset returned wrong value"); 355 if (U_FAILURE(status)) { errln("FAIL: GregorianCalendar::set failed"); return; } 356 delete gc; 357 delete time_zone; 358 } 359 360 // ------------------------------------- 361 362 /** 363 * Test the call which retrieves the available IDs. 364 */ 365 void 366 TimeZoneTest::TestGetAvailableIDs913() 367 { 368 UErrorCode ec = U_ZERO_ERROR; 369 int32_t i; 370 371 #ifdef U_USE_TIMEZONE_OBSOLETE_2_8 372 // Test legacy API -- remove these tests when the corresponding API goes away (duh) 373 int32_t numIDs = -1; 374 const UnicodeString** ids = TimeZone::createAvailableIDs(numIDs); 375 if (ids == 0 || numIDs < 1) { 376 errln("FAIL: createAvailableIDs()"); 377 } else { 378 UnicodeString buf("TimeZone::createAvailableIDs() = { "); 379 for(i=0; i<numIDs; ++i) { 380 if (i) buf.append(", "); 381 buf.append(*ids[i]); 382 } 383 buf.append(" } "); 384 logln(buf + numIDs); 385 // we own the array; the caller owns the contained strings (yuck) 386 uprv_free(ids); 387 } 388 389 numIDs = -1; 390 ids = TimeZone::createAvailableIDs(-8*U_MILLIS_PER_HOUR, numIDs); 391 if (ids == 0 || numIDs < 1) { 392 errln("FAIL: createAvailableIDs(-8:00)"); 393 } else { 394 UnicodeString buf("TimeZone::createAvailableIDs(-8:00) = { "); 395 for(i=0; i<numIDs; ++i) { 396 if (i) buf.append(", "); 397 buf.append(*ids[i]); 398 } 399 buf.append(" } "); 400 logln(buf + numIDs); 401 // we own the array; the caller owns the contained strings (yuck) 402 uprv_free(ids); 403 } 404 numIDs = -1; 405 ids = TimeZone::createAvailableIDs("US", numIDs); 406 if (ids == 0 || numIDs < 1) { 407 errln("FAIL: createAvailableIDs(US) ids=%d, numIDs=%d", ids, numIDs); 408 } else { 409 UnicodeString buf("TimeZone::createAvailableIDs(US) = { "); 410 for(i=0; i<numIDs; ++i) { 411 if (i) buf.append(", "); 412 buf.append(*ids[i]); 413 } 414 buf.append(" } "); 415 logln(buf + numIDs); 416 // we own the array; the caller owns the contained strings (yuck) 417 uprv_free(ids); 418 } 419 #endif 420 421 UnicodeString str; 422 UnicodeString *buf = new UnicodeString("TimeZone::createEnumeration() = { "); 423 int32_t s_length; 424 StringEnumeration* s = TimeZone::createEnumeration(); 425 if (s == NULL) { 426 dataerrln("Unable to create TimeZone enumeration"); 427 return; 428 } 429 s_length = s->count(ec); 430 for (i = 0; i < s_length;++i) { 431 if (i > 0) *buf += ", "; 432 if ((i & 1) == 0) { 433 *buf += *s->snext(ec); 434 } else { 435 *buf += UnicodeString(s->next(NULL, ec), ""); 436 } 437 438 if((i % 5) == 4) { 439 // replace s with a clone of itself 440 StringEnumeration *s2 = s->clone(); 441 if(s2 == NULL || s_length != s2->count(ec)) { 442 errln("TimezoneEnumeration.clone() failed"); 443 } else { 444 delete s; 445 s = s2; 446 } 447 } 448 } 449 *buf += " };"; 450 logln(*buf); 451 452 /* Confirm that the following zones can be retrieved: The first 453 * zone, the last zone, and one in-between. This tests the binary 454 * search through the system zone data. 455 */ 456 s->reset(ec); 457 int32_t middle = s_length/2; 458 for (i=0; i<s_length; ++i) { 459 const UnicodeString* id = s->snext(ec); 460 if (i==0 || i==middle || i==(s_length-1)) { 461 TimeZone *z = TimeZone::createTimeZone(*id); 462 if (z == 0) { 463 errln(UnicodeString("FAIL: createTimeZone(") + 464 *id + ") -> 0"); 465 } else if (z->getID(str) != *id) { 466 errln(UnicodeString("FAIL: createTimeZone(") + 467 *id + ") -> zone " + str); 468 } else { 469 logln(UnicodeString("OK: createTimeZone(") + 470 *id + ") succeeded"); 471 } 472 delete z; 473 } 474 } 475 delete s; 476 477 buf->truncate(0); 478 *buf += "TimeZone::createEnumeration(GMT+01:00) = { "; 479 480 s = TimeZone::createEnumeration(1 * U_MILLIS_PER_HOUR); 481 s_length = s->count(ec); 482 for (i = 0; i < s_length;++i) { 483 if (i > 0) *buf += ", "; 484 *buf += *s->snext(ec); 485 } 486 delete s; 487 *buf += " };"; 488 logln(*buf); 489 490 491 buf->truncate(0); 492 *buf += "TimeZone::createEnumeration(US) = { "; 493 494 s = TimeZone::createEnumeration("US"); 495 s_length = s->count(ec); 496 for (i = 0; i < s_length;++i) { 497 if (i > 0) *buf += ", "; 498 *buf += *s->snext(ec); 499 } 500 *buf += " };"; 501 logln(*buf); 502 503 TimeZone *tz = TimeZone::createTimeZone("PST"); 504 if (tz != 0) logln("getTimeZone(PST) = " + tz->getID(str)); 505 else errln("FAIL: getTimeZone(PST) = null"); 506 delete tz; 507 tz = TimeZone::createTimeZone("America/Los_Angeles"); 508 if (tz != 0) logln("getTimeZone(America/Los_Angeles) = " + tz->getID(str)); 509 else errln("FAIL: getTimeZone(PST) = null"); 510 delete tz; 511 512 // @bug 4096694 513 tz = TimeZone::createTimeZone("NON_EXISTENT"); 514 UnicodeString temp; 515 if (tz == 0) 516 errln("FAIL: getTimeZone(NON_EXISTENT) = null"); 517 else if (tz->getID(temp) != UCAL_UNKNOWN_ZONE_ID) 518 errln("FAIL: getTimeZone(NON_EXISTENT) = " + temp); 519 delete tz; 520 521 delete buf; 522 delete s; 523 } 524 525 void 526 TimeZoneTest::TestGetAvailableIDsNew() 527 { 528 UErrorCode ec = U_ZERO_ERROR; 529 StringEnumeration *any, *canonical, *canonicalLoc; 530 StringEnumeration *any_US, *canonical_US, *canonicalLoc_US; 531 StringEnumeration *any_W5, *any_CA_W5; 532 StringEnumeration *any_US_E14; 533 int32_t rawOffset; 534 const UnicodeString *id1, *id2; 535 UnicodeString canonicalID; 536 UBool isSystemID; 537 char region[4]; 538 int32_t zoneCount; 539 540 any = canonical = canonicalLoc = any_US = canonical_US = canonicalLoc_US = any_W5 = any_CA_W5 = any_US_E14 = NULL; 541 542 any = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, NULL, NULL, ec); 543 if (U_FAILURE(ec)) { 544 dataerrln("Failed to create enumration for ANY"); 545 goto cleanup; 546 } 547 548 canonical = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, ec); 549 if (U_FAILURE(ec)) { 550 errln("Failed to create enumration for CANONICAL"); 551 goto cleanup; 552 } 553 554 canonicalLoc = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL_LOCATION, NULL, NULL, ec); 555 if (U_FAILURE(ec)) { 556 errln("Failed to create enumration for CANONICALLOC"); 557 goto cleanup; 558 } 559 560 any_US = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, "US", NULL, ec); 561 if (U_FAILURE(ec)) { 562 errln("Failed to create enumration for ANY_US"); 563 goto cleanup; 564 } 565 566 canonical_US = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, "US", NULL, ec); 567 if (U_FAILURE(ec)) { 568 errln("Failed to create enumration for CANONICAL_US"); 569 goto cleanup; 570 } 571 572 canonicalLoc_US = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL_LOCATION, "US", NULL, ec); 573 if (U_FAILURE(ec)) { 574 errln("Failed to create enumration for CANONICALLOC_US"); 575 goto cleanup; 576 } 577 578 rawOffset = (-5)*60*60*1000; 579 any_W5 = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, NULL, &rawOffset, ec); 580 if (U_FAILURE(ec)) { 581 errln("Failed to create enumration for ANY_W5"); 582 goto cleanup; 583 } 584 585 any_CA_W5 = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, "CA", &rawOffset, ec); 586 if (U_FAILURE(ec)) { 587 errln("Failed to create enumration for ANY_CA_W5"); 588 goto cleanup; 589 } 590 591 rawOffset = 14*60*60*1000; 592 any_US_E14 = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, "US", &rawOffset, ec); 593 if (U_FAILURE(ec)) { 594 errln("Failed to create enumration for ANY_US_E14"); 595 goto cleanup; 596 } 597 598 checkContainsAll(any, "ANY", canonical, "CANONICAL"); 599 checkContainsAll(canonical, "CANONICAL", canonicalLoc, "CANONICALLOC"); 600 601 checkContainsAll(any, "ANY", any_US, "ANY_US"); 602 checkContainsAll(canonical, "CANONICAL", canonical_US, "CANONICAL_US"); 603 checkContainsAll(canonicalLoc, "CANONICALLOC", canonicalLoc_US, "CANONICALLOC_US"); 604 605 checkContainsAll(any_US, "ANY_US", canonical_US, "CANONICAL_US"); 606 checkContainsAll(canonical_US, "CANONICAL_US", canonicalLoc_US, "CANONICALLOC_US"); 607 608 checkContainsAll(any, "ANY", any_W5, "ANY_W5"); 609 checkContainsAll(any_W5, "ANY_W5", any_CA_W5, "ANY_CA_W5"); 610 611 // And ID in any set, but not in canonical set must not be a canonical ID 612 any->reset(ec); 613 while ((id1 = any->snext(ec)) != NULL) { 614 UBool found = FALSE; 615 canonical->reset(ec); 616 while ((id2 = canonical->snext(ec)) != NULL) { 617 if (*id1 == *id2) { 618 found = TRUE; 619 break; 620 } 621 } 622 if (U_FAILURE(ec)) { 623 break; 624 } 625 if (!found) { 626 TimeZone::getCanonicalID(*id1, canonicalID, isSystemID, ec); 627 if (U_FAILURE(ec)) { 628 break; 629 } 630 if (*id1 == canonicalID) { 631 errln((UnicodeString)"FAIL: canonicalID [" + *id1 + "] is not in CANONICAL"); 632 } 633 if (!isSystemID) { 634 errln((UnicodeString)"FAIL: ANY contains non-system ID: " + *id1); 635 } 636 } 637 } 638 if (U_FAILURE(ec)) { 639 errln("Error checking IDs in ANY, but not in CANONICAL"); 640 ec = U_ZERO_ERROR; 641 } 642 643 // canonical set must contains only canonical IDs 644 canonical->reset(ec); 645 while ((id1 = canonical->snext(ec)) != NULL) { 646 TimeZone::getCanonicalID(*id1, canonicalID, isSystemID, ec); 647 if (U_FAILURE(ec)) { 648 break; 649 } 650 if (*id1 != canonicalID) { 651 errln((UnicodeString)"FAIL: CANONICAL contains non-canonical ID: " + *id1); 652 } 653 if (!isSystemID) { 654 errln((UnicodeString)"FAILE: CANONICAL contains non-system ID: " + *id1); 655 } 656 } 657 if (U_FAILURE(ec)) { 658 errln("Error checking IDs in CANONICAL"); 659 ec = U_ZERO_ERROR; 660 } 661 662 // canonicalLoc set must contain only canonical location IDs 663 canonicalLoc->reset(ec); 664 while ((id1 = canonicalLoc->snext(ec)) != NULL) { 665 TimeZone::getRegion(*id1, region, sizeof(region), ec); 666 if (U_FAILURE(ec)) { 667 break; 668 } 669 if (uprv_strcmp(region, "001") == 0) { 670 errln((UnicodeString)"FAIL: CANONICALLOC contains non location zone: " + *id1); 671 } 672 } 673 if (U_FAILURE(ec)) { 674 errln("Error checking IDs in CANONICALLOC"); 675 ec = U_ZERO_ERROR; 676 } 677 678 // any_US must contain only US zones 679 any_US->reset(ec); 680 while ((id1 = any_US->snext(ec)) != NULL) { 681 TimeZone::getRegion(*id1, region, sizeof(region), ec); 682 if (U_FAILURE(ec)) { 683 break; 684 } 685 if (uprv_strcmp(region, "US") != 0) { 686 errln((UnicodeString)"FAIL: ANY_US contains non-US zone ID: " + *id1); 687 } 688 } 689 if (U_FAILURE(ec)) { 690 errln("Error checking IDs in ANY_US"); 691 ec = U_ZERO_ERROR; 692 } 693 694 // any_W5 must contain only GMT-05:00 zones 695 any_W5->reset(ec); 696 while ((id1 = any_W5->snext(ec)) != NULL) { 697 TimeZone *tz = TimeZone::createTimeZone(*id1); 698 if (tz->getRawOffset() != (-5)*60*60*1000) { 699 errln((UnicodeString)"FAIL: ANY_W5 contains a zone whose offset is not -05:00: " + *id1); 700 } 701 delete tz; 702 } 703 if (U_FAILURE(ec)) { 704 errln("Error checking IDs in ANY_W5"); 705 ec = U_ZERO_ERROR; 706 } 707 708 // No US zone swith GMT+14:00 709 zoneCount = any_US_E14->count(ec); 710 if (U_FAILURE(ec)) { 711 errln("Error checking IDs in ANY_US_E14"); 712 ec = U_ZERO_ERROR; 713 } else if (zoneCount != 0) { 714 errln("FAIL: ANY_US_E14 must be empty"); 715 } 716 717 cleanup: 718 delete any; 719 delete canonical; 720 delete canonicalLoc; 721 delete any_US; 722 delete canonical_US; 723 delete canonicalLoc_US; 724 delete any_W5; 725 delete any_CA_W5; 726 delete any_US_E14; 727 } 728 729 void 730 TimeZoneTest::checkContainsAll(StringEnumeration *s1, const char *name1, 731 StringEnumeration *s2, const char *name2) 732 { 733 UErrorCode ec = U_ZERO_ERROR; 734 const UnicodeString *id1, *id2; 735 736 s2->reset(ec); 737 738 while ((id2 = s2->snext(ec)) != NULL) { 739 UBool found = FALSE; 740 s1->reset(ec); 741 while ((id1 = s1->snext(ec)) != NULL) { 742 if (*id1 == *id2) { 743 found = TRUE; 744 break; 745 } 746 } 747 if (!found) { 748 errln((UnicodeString)"FAIL: " + name1 + "does not contain " 749 + *id2 + " in " + name2); 750 } 751 } 752 753 if (U_FAILURE(ec)) { 754 errln((UnicodeString)"Error checkContainsAll for " + name1 + " - " + name2); 755 } 756 } 757 758 /** 759 * NOTE: As of ICU 2.8, this test confirms that the "tz.alias" 760 * file, used to build ICU alias zones, is working. It also 761 * looks at some genuine Olson compatibility IDs. [aliu] 762 * 763 * This test is problematic. It should really just confirm that 764 * the list of compatibility zone IDs exist and are somewhat 765 * meaningful (that is, they aren't all aliases of GMT). It goes a 766 * bit further -- it hard-codes expectations about zone behavior, 767 * when in fact zones are redefined quite frequently. ICU's build 768 * process means that it is easy to update ICU to contain the 769 * latest Olson zone data, but if a zone tested here changes, then 770 * this test will fail. I have updated the test for 1999j data, 771 * but further updates will probably be required. Note that some 772 * of the concerts listed below no longer apply -- in particular, 773 * we do NOT overwrite real UNIX zones with 3-letter IDs. There 774 * are two points of overlap as of 1999j: MET and EET. These are 775 * both real UNIX zones, so we just use the official 776 * definition. This test has been updated to reflect this. 777 * 12/3/99 aliu 778 * 779 * Added tests for additional zones and aliases from the icuzones file. 780 * Markus Scherer 2006-nov-06 781 * 782 * [srl - from java - 7/5/1998] 783 * @bug 4130885 784 * Certain short zone IDs, used since 1.1.x, are incorrect. 785 * 786 * The worst of these is: 787 * 788 * "CAT" (Central African Time) should be GMT+2:00, but instead returns a 789 * zone at GMT-1:00. The zone at GMT-1:00 should be called EGT, CVT, EGST, 790 * or AZOST, depending on which zone is meant, but in no case is it CAT. 791 * 792 * Other wrong zone IDs: 793 * 794 * ECT (European Central Time) GMT+1:00: ECT is Ecuador Time, 795 * GMT-5:00. European Central time is abbreviated CEST. 796 * 797 * SST (Solomon Island Time) GMT+11:00. SST is actually Samoa Standard Time, 798 * GMT-11:00. Solomon Island time is SBT. 799 * 800 * NST (New Zealand Time) GMT+12:00. NST is the abbreviation for 801 * Newfoundland Standard Time, GMT-3:30. New Zealanders use NZST. 802 * 803 * AST (Alaska Standard Time) GMT-9:00. [This has already been noted in 804 * another bug.] It should be "AKST". AST is Atlantic Standard Time, 805 * GMT-4:00. 806 * 807 * PNT (Phoenix Time) GMT-7:00. PNT usually means Pitcairn Time, 808 * GMT-8:30. There is no standard abbreviation for Phoenix time, as distinct 809 * from MST with daylight savings. 810 * 811 * In addition to these problems, a number of zones are FAKE. That is, they 812 * don't match what people use in the real world. 813 * 814 * FAKE zones: 815 * 816 * EET (should be EEST) 817 * ART (should be EEST) 818 * MET (should be IRST) 819 * NET (should be AMST) 820 * PLT (should be PKT) 821 * BST (should be BDT) 822 * VST (should be ICT) 823 * CTT (should be CST) + 824 * ACT (should be CST) + 825 * AET (should be EST) + 826 * MIT (should be WST) + 827 * IET (should be EST) + 828 * PRT (should be AST) + 829 * CNT (should be NST) 830 * AGT (should be ARST) 831 * BET (should be EST) + 832 * 833 * + A zone with the correct name already exists and means something 834 * else. E.g., EST usually indicates the US Eastern zone, so it cannot be 835 * used for Brazil (BET). 836 */ 837 void TimeZoneTest::TestShortZoneIDs() 838 { 839 int32_t i; 840 // Create a small struct to hold the array 841 struct 842 { 843 const char *id; 844 int32_t offset; 845 UBool daylight; 846 } 847 kReferenceList [] = 848 { 849 {"HST", -600, FALSE}, // Olson northamerica -10:00 850 {"AST", -540, TRUE}, // ICU Link - America/Anchorage 851 {"PST", -480, TRUE}, // ICU Link - America/Los_Angeles 852 {"PNT", -420, FALSE}, // ICU Link - America/Phoenix 853 {"MST", -420, FALSE}, // updated Aug 2003 aliu 854 {"CST", -360, TRUE}, // Olson northamerica -7:00 855 {"IET", -300, TRUE}, // ICU Link - America/Indiana/Indianapolis 856 {"EST", -300, FALSE}, // Olson northamerica -5:00 857 {"PRT", -240, FALSE}, // ICU Link - America/Puerto_Rico 858 {"CNT", -210, TRUE}, // ICU Link - America/St_Johns 859 {"AGT", -180, FALSE}, // ICU Link - America/Argentina/Buenos_Aires 860 {"BET", -180, TRUE}, // ICU Link - America/Sao_Paulo 861 {"GMT", 0, FALSE}, // Olson etcetera Link - Etc/GMT 862 {"UTC", 0, FALSE}, // Olson etcetera 0 863 {"ECT", 60, TRUE}, // ICU Link - Europe/Paris 864 {"MET", 60, TRUE}, // Olson europe 1:00 C-Eur 865 {"CAT", 120, FALSE}, // ICU Link - Africa/Harare 866 {"ART", 120, FALSE}, // ICU Link - Africa/Cairo 867 {"EET", 120, TRUE}, // Olson europe 2:00 EU 868 {"EAT", 180, FALSE}, // ICU Link - Africa/Addis_Ababa 869 {"NET", 240, FALSE}, // ICU Link - Asia/Yerevan 870 {"PLT", 300, FALSE}, // ICU Link - Asia/Karachi 871 {"IST", 330, FALSE}, // ICU Link - Asia/Kolkata 872 {"BST", 360, FALSE}, // ICU Link - Asia/Dhaka 873 {"VST", 420, FALSE}, // ICU Link - Asia/Ho_Chi_Minh 874 {"CTT", 480, FALSE}, // ICU Link - Asia/Shanghai 875 {"JST", 540, FALSE}, // ICU Link - Asia/Tokyo 876 {"ACT", 570, FALSE}, // ICU Link - Australia/Darwin 877 {"AET", 600, TRUE}, // ICU Link - Australia/Sydney 878 {"SST", 660, FALSE}, // ICU Link - Pacific/Guadalcanal 879 {"NST", 720, TRUE}, // ICU Link - Pacific/Auckland 880 {"MIT", 780, TRUE}, // ICU Link - Pacific/Apia 881 882 {"Etc/Unknown", 0, FALSE}, // CLDR 883 884 {"SystemV/AST4ADT", -240, TRUE}, 885 {"SystemV/EST5EDT", -300, TRUE}, 886 {"SystemV/CST6CDT", -360, TRUE}, 887 {"SystemV/MST7MDT", -420, TRUE}, 888 {"SystemV/PST8PDT", -480, TRUE}, 889 {"SystemV/YST9YDT", -540, TRUE}, 890 {"SystemV/AST4", -240, FALSE}, 891 {"SystemV/EST5", -300, FALSE}, 892 {"SystemV/CST6", -360, FALSE}, 893 {"SystemV/MST7", -420, FALSE}, 894 {"SystemV/PST8", -480, FALSE}, 895 {"SystemV/YST9", -540, FALSE}, 896 {"SystemV/HST10", -600, FALSE}, 897 898 {"",0,FALSE} 899 }; 900 901 for(i=0;kReferenceList[i].id[0];i++) { 902 UnicodeString itsID(kReferenceList[i].id); 903 UBool ok = TRUE; 904 // Check existence. 905 TimeZone *tz = TimeZone::createTimeZone(itsID); 906 if (!tz || (kReferenceList[i].offset != 0 && *tz == *TimeZone::getGMT())) { 907 errln("FAIL: Time Zone " + itsID + " does not exist!"); 908 continue; 909 } 910 911 // Check daylight usage. 912 UBool usesDaylight = tz->useDaylightTime(); 913 if (usesDaylight != kReferenceList[i].daylight) { 914 if (!isDevelopmentBuild) { 915 logln("Warning: Time Zone " + itsID + " use daylight is " + 916 (usesDaylight?"TRUE":"FALSE") + 917 " but it should be " + 918 ((kReferenceList[i].daylight)?"TRUE":"FALSE")); 919 } else { 920 dataerrln("FAIL: Time Zone " + itsID + " use daylight is " + 921 (usesDaylight?"TRUE":"FALSE") + 922 " but it should be " + 923 ((kReferenceList[i].daylight)?"TRUE":"FALSE")); 924 } 925 ok = FALSE; 926 } 927 928 // Check offset 929 int32_t offsetInMinutes = tz->getRawOffset()/60000; 930 if (offsetInMinutes != kReferenceList[i].offset) { 931 if (!isDevelopmentBuild) { 932 logln("FAIL: Time Zone " + itsID + " raw offset is " + 933 offsetInMinutes + 934 " but it should be " + kReferenceList[i].offset); 935 } else { 936 dataerrln("FAIL: Time Zone " + itsID + " raw offset is " + 937 offsetInMinutes + 938 " but it should be " + kReferenceList[i].offset); 939 } 940 ok = FALSE; 941 } 942 943 if (ok) { 944 logln("OK: " + itsID + 945 " useDaylightTime() & getRawOffset() as expected"); 946 } 947 delete tz; 948 } 949 950 951 // OK now test compat 952 logln("Testing for compatibility zones"); 953 954 const char* compatibilityMap[] = { 955 // This list is copied from tz.alias. If tz.alias 956 // changes, this list must be updated. Current as of Mar 2007 957 "ACT", "Australia/Darwin", 958 "AET", "Australia/Sydney", 959 "AGT", "America/Buenos_Aires", 960 "ART", "Africa/Cairo", 961 "AST", "America/Anchorage", 962 "BET", "America/Sao_Paulo", 963 "BST", "Asia/Dhaka", // # spelling changed in 2000h; was Asia/Dacca 964 "CAT", "Africa/Harare", 965 "CNT", "America/St_Johns", 966 "CST", "America/Chicago", 967 "CTT", "Asia/Shanghai", 968 "EAT", "Africa/Addis_Ababa", 969 "ECT", "Europe/Paris", 970 // EET Europe/Istanbul # EET is a standard UNIX zone 971 // "EST", "America/New_York", # Defined as -05:00 972 // "HST", "Pacific/Honolulu", # Defined as -10:00 973 "IET", "America/Indianapolis", 974 "IST", "Asia/Calcutta", 975 "JST", "Asia/Tokyo", 976 // MET Asia/Tehran # MET is a standard UNIX zone 977 "MIT", "Pacific/Apia", 978 // "MST", "America/Denver", # Defined as -07:00 979 "NET", "Asia/Yerevan", 980 "NST", "Pacific/Auckland", 981 "PLT", "Asia/Karachi", 982 "PNT", "America/Phoenix", 983 "PRT", "America/Puerto_Rico", 984 "PST", "America/Los_Angeles", 985 "SST", "Pacific/Guadalcanal", 986 "UTC", "Etc/GMT", 987 "VST", "Asia/Saigon", 988 "","","" 989 }; 990 991 for (i=0;*compatibilityMap[i];i+=2) { 992 UnicodeString itsID; 993 994 const char *zone1 = compatibilityMap[i]; 995 const char *zone2 = compatibilityMap[i+1]; 996 997 TimeZone *tz1 = TimeZone::createTimeZone(zone1); 998 TimeZone *tz2 = TimeZone::createTimeZone(zone2); 999 1000 if (!tz1) { 1001 errln(UnicodeString("FAIL: Could not find short ID zone ") + zone1); 1002 } 1003 if (!tz2) { 1004 errln(UnicodeString("FAIL: Could not find long ID zone ") + zone2); 1005 } 1006 1007 if (tz1 && tz2) { 1008 // make NAME same so comparison will only look at the rest 1009 tz2->setID(tz1->getID(itsID)); 1010 1011 if (*tz1 != *tz2) { 1012 errln("FAIL: " + UnicodeString(zone1) + 1013 " != " + UnicodeString(zone2)); 1014 } else { 1015 logln("OK: " + UnicodeString(zone1) + 1016 " == " + UnicodeString(zone2)); 1017 } 1018 } 1019 1020 delete tz1; 1021 delete tz2; 1022 } 1023 } 1024 1025 1026 /** 1027 * Utility function for TestCustomParse 1028 */ 1029 UnicodeString& TimeZoneTest::formatOffset(int32_t offset, UnicodeString &rv) { 1030 rv.remove(); 1031 UChar sign = 0x002B; 1032 if (offset < 0) { 1033 sign = 0x002D; 1034 offset = -offset; 1035 } 1036 1037 int32_t s = offset % 60; 1038 offset /= 60; 1039 int32_t m = offset % 60; 1040 int32_t h = offset / 60; 1041 1042 rv += (UChar)(sign); 1043 if (h >= 10) { 1044 rv += (UChar)(0x0030 + (h/10)); 1045 } else { 1046 rv += (UChar)0x0030; 1047 } 1048 rv += (UChar)(0x0030 + (h%10)); 1049 1050 rv += (UChar)0x003A; /* ':' */ 1051 if (m >= 10) { 1052 rv += (UChar)(0x0030 + (m/10)); 1053 } else { 1054 rv += (UChar)0x0030; 1055 } 1056 rv += (UChar)(0x0030 + (m%10)); 1057 1058 if (s) { 1059 rv += (UChar)0x003A; /* ':' */ 1060 if (s >= 10) { 1061 rv += (UChar)(0x0030 + (s/10)); 1062 } else { 1063 rv += (UChar)0x0030; 1064 } 1065 rv += (UChar)(0x0030 + (s%10)); 1066 } 1067 return rv; 1068 } 1069 1070 /** 1071 * Utility function for TestCustomParse, generating time zone ID 1072 * string for the give offset. 1073 */ 1074 UnicodeString& TimeZoneTest::formatTZID(int32_t offset, UnicodeString &rv) { 1075 rv.remove(); 1076 UChar sign = 0x002B; 1077 if (offset < 0) { 1078 sign = 0x002D; 1079 offset = -offset; 1080 } 1081 1082 int32_t s = offset % 60; 1083 offset /= 60; 1084 int32_t m = offset % 60; 1085 int32_t h = offset / 60; 1086 1087 rv += "GMT"; 1088 rv += (UChar)(sign); 1089 if (h >= 10) { 1090 rv += (UChar)(0x0030 + (h/10)); 1091 } else { 1092 rv += (UChar)0x0030; 1093 } 1094 rv += (UChar)(0x0030 + (h%10)); 1095 rv += (UChar)0x003A; 1096 if (m >= 10) { 1097 rv += (UChar)(0x0030 + (m/10)); 1098 } else { 1099 rv += (UChar)0x0030; 1100 } 1101 rv += (UChar)(0x0030 + (m%10)); 1102 1103 if (s) { 1104 rv += (UChar)0x003A; 1105 if (s >= 10) { 1106 rv += (UChar)(0x0030 + (s/10)); 1107 } else { 1108 rv += (UChar)0x0030; 1109 } 1110 rv += (UChar)(0x0030 + (s%10)); 1111 } 1112 return rv; 1113 } 1114 1115 /** 1116 * As part of the VM fix (see CCC approved RFE 4028006, bug 1117 * 4044013), TimeZone.getTimeZone() has been modified to recognize 1118 * generic IDs of the form GMT[+-]hh:mm, GMT[+-]hhmm, and 1119 * GMT[+-]hh. Test this behavior here. 1120 * 1121 * @bug 4044013 1122 */ 1123 void TimeZoneTest::TestCustomParse() 1124 { 1125 int32_t i; 1126 const int32_t kUnparseable = 604800; // the number of seconds in a week. More than any offset should be. 1127 1128 struct 1129 { 1130 const char *customId; 1131 int32_t expectedOffset; 1132 } 1133 kData[] = 1134 { 1135 // ID Expected offset in seconds 1136 {"GMT", kUnparseable}, //Isn't custom. [returns normal GMT] 1137 {"GMT-YOUR.AD.HERE", kUnparseable}, 1138 {"GMT0", kUnparseable}, 1139 {"GMT+0", (0)}, 1140 {"GMT+1", (1*60*60)}, 1141 {"GMT-0030", (-30*60)}, 1142 {"GMT+15:99", kUnparseable}, 1143 {"GMT+", kUnparseable}, 1144 {"GMT-", kUnparseable}, 1145 {"GMT+0:", kUnparseable}, 1146 {"GMT-:", kUnparseable}, 1147 {"GMT-YOUR.AD.HERE", kUnparseable}, 1148 {"GMT+0010", (10*60)}, // Interpret this as 00:10 1149 {"GMT-10", (-10*60*60)}, 1150 {"GMT+30", kUnparseable}, 1151 {"GMT-3:30", (-(3*60+30)*60)}, 1152 {"GMT-230", (-(2*60+30)*60)}, 1153 {"GMT+05:13:05", ((5*60+13)*60+5)}, 1154 {"GMT-71023", (-((7*60+10)*60+23))}, 1155 {"GMT+01:23:45:67", kUnparseable}, 1156 {"GMT+01:234", kUnparseable}, 1157 {"GMT-2:31:123", kUnparseable}, 1158 {"GMT+3:75", kUnparseable}, 1159 {"GMT-01010101", kUnparseable}, 1160 {0, 0} 1161 }; 1162 1163 for (i=0; kData[i].customId != 0; i++) { 1164 UnicodeString id(kData[i].customId); 1165 int32_t exp = kData[i].expectedOffset; 1166 TimeZone *zone = TimeZone::createTimeZone(id); 1167 UnicodeString itsID, temp; 1168 1169 if (dynamic_cast<OlsonTimeZone *>(zone) != NULL) { 1170 logln(id + " -> Olson time zone"); 1171 } else { 1172 zone->getID(itsID); 1173 int32_t ioffset = zone->getRawOffset()/1000; 1174 UnicodeString offset, expectedID; 1175 formatOffset(ioffset, offset); 1176 formatTZID(ioffset, expectedID); 1177 logln(id + " -> " + itsID + " " + offset); 1178 if (exp == kUnparseable && itsID != UCAL_UNKNOWN_ZONE_ID) { 1179 errln("Expected parse failure for " + id + 1180 ", got offset of " + offset + 1181 ", id " + itsID); 1182 } 1183 // JDK 1.3 creates custom zones with the ID "Custom" 1184 // JDK 1.4 creates custom zones with IDs of the form "GMT+02:00" 1185 // ICU creates custom zones with IDs of the form "GMT+02:00" 1186 else if (exp != kUnparseable && (ioffset != exp || itsID != expectedID)) { 1187 dataerrln("Expected offset of " + formatOffset(exp, temp) + 1188 ", id " + expectedID + 1189 ", for " + id + 1190 ", got offset of " + offset + 1191 ", id " + itsID); 1192 } 1193 } 1194 delete zone; 1195 } 1196 } 1197 1198 void 1199 TimeZoneTest::TestAliasedNames() 1200 { 1201 struct { 1202 const char *from; 1203 const char *to; 1204 } kData[] = { 1205 /* Generated by org.unicode.cldr.tool.CountItems */ 1206 1207 /* zoneID, canonical zoneID */ 1208 {"Africa/Timbuktu", "Africa/Bamako"}, 1209 {"America/Argentina/Buenos_Aires", "America/Buenos_Aires"}, 1210 {"America/Argentina/Catamarca", "America/Catamarca"}, 1211 {"America/Argentina/ComodRivadavia", "America/Catamarca"}, 1212 {"America/Argentina/Cordoba", "America/Cordoba"}, 1213 {"America/Argentina/Jujuy", "America/Jujuy"}, 1214 {"America/Argentina/Mendoza", "America/Mendoza"}, 1215 {"America/Atka", "America/Adak"}, 1216 {"America/Ensenada", "America/Tijuana"}, 1217 {"America/Fort_Wayne", "America/Indiana/Indianapolis"}, 1218 {"America/Indianapolis", "America/Indiana/Indianapolis"}, 1219 {"America/Knox_IN", "America/Indiana/Knox"}, 1220 {"America/Louisville", "America/Kentucky/Louisville"}, 1221 {"America/Porto_Acre", "America/Rio_Branco"}, 1222 {"America/Rosario", "America/Cordoba"}, 1223 {"America/Virgin", "America/St_Thomas"}, 1224 {"Asia/Ashkhabad", "Asia/Ashgabat"}, 1225 {"Asia/Chungking", "Asia/Chongqing"}, 1226 {"Asia/Dacca", "Asia/Dhaka"}, 1227 {"Asia/Istanbul", "Europe/Istanbul"}, 1228 {"Asia/Macao", "Asia/Macau"}, 1229 {"Asia/Tel_Aviv", "Asia/Jerusalem"}, 1230 {"Asia/Thimbu", "Asia/Thimphu"}, 1231 {"Asia/Ujung_Pandang", "Asia/Makassar"}, 1232 {"Asia/Ulan_Bator", "Asia/Ulaanbaatar"}, 1233 {"Australia/ACT", "Australia/Sydney"}, 1234 {"Australia/Canberra", "Australia/Sydney"}, 1235 {"Australia/LHI", "Australia/Lord_Howe"}, 1236 {"Australia/NSW", "Australia/Sydney"}, 1237 {"Australia/North", "Australia/Darwin"}, 1238 {"Australia/Queensland", "Australia/Brisbane"}, 1239 {"Australia/South", "Australia/Adelaide"}, 1240 {"Australia/Tasmania", "Australia/Hobart"}, 1241 {"Australia/Victoria", "Australia/Melbourne"}, 1242 {"Australia/West", "Australia/Perth"}, 1243 {"Australia/Yancowinna", "Australia/Broken_Hill"}, 1244 {"Brazil/Acre", "America/Rio_Branco"}, 1245 {"Brazil/DeNoronha", "America/Noronha"}, 1246 {"Brazil/East", "America/Sao_Paulo"}, 1247 {"Brazil/West", "America/Manaus"}, 1248 {"Canada/Atlantic", "America/Halifax"}, 1249 {"Canada/Central", "America/Winnipeg"}, 1250 {"Canada/East-Saskatchewan", "America/Regina"}, 1251 {"Canada/Eastern", "America/Toronto"}, 1252 {"Canada/Mountain", "America/Edmonton"}, 1253 {"Canada/Newfoundland", "America/St_Johns"}, 1254 {"Canada/Pacific", "America/Vancouver"}, 1255 {"Canada/Saskatchewan", "America/Regina"}, 1256 {"Canada/Yukon", "America/Whitehorse"}, 1257 {"Chile/Continental", "America/Santiago"}, 1258 {"Chile/EasterIsland", "Pacific/Easter"}, 1259 {"Cuba", "America/Havana"}, 1260 {"Egypt", "Africa/Cairo"}, 1261 {"Eire", "Europe/Dublin"}, 1262 {"Etc/GMT+0", "Etc/GMT"}, 1263 {"Etc/GMT-0", "Etc/GMT"}, 1264 {"Etc/GMT0", "Etc/GMT"}, 1265 {"Etc/Greenwich", "Etc/GMT"}, 1266 {"Etc/UCT", "Etc/GMT"}, 1267 {"Etc/UTC", "Etc/GMT"}, 1268 {"Etc/Universal", "Etc/GMT"}, 1269 {"Etc/Zulu", "Etc/GMT"}, 1270 {"Europe/Belfast", "Europe/London"}, 1271 {"Europe/Nicosia", "Asia/Nicosia"}, 1272 {"Europe/Tiraspol", "Europe/Chisinau"}, 1273 {"GB", "Europe/London"}, 1274 {"GB-Eire", "Europe/London"}, 1275 {"GMT", "Etc/GMT"}, 1276 {"GMT+0", "Etc/GMT"}, 1277 {"GMT-0", "Etc/GMT"}, 1278 {"GMT0", "Etc/GMT"}, 1279 {"Greenwich", "Etc/GMT"}, 1280 {"Hongkong", "Asia/Hong_Kong"}, 1281 {"Iceland", "Atlantic/Reykjavik"}, 1282 {"Iran", "Asia/Tehran"}, 1283 {"Israel", "Asia/Jerusalem"}, 1284 {"Jamaica", "America/Jamaica"}, 1285 {"Japan", "Asia/Tokyo"}, 1286 {"Kwajalein", "Pacific/Kwajalein"}, 1287 {"Libya", "Africa/Tripoli"}, 1288 {"Mexico/BajaNorte", "America/Tijuana"}, 1289 {"Mexico/BajaSur", "America/Mazatlan"}, 1290 {"Mexico/General", "America/Mexico_City"}, 1291 {"NZ", "Pacific/Auckland"}, 1292 {"NZ-CHAT", "Pacific/Chatham"}, 1293 {"Navajo", "America/Shiprock"}, 1294 {"PRC", "Asia/Shanghai"}, 1295 {"Pacific/Samoa", "Pacific/Pago_Pago"}, 1296 {"Pacific/Yap", "Pacific/Truk"}, 1297 {"Poland", "Europe/Warsaw"}, 1298 {"Portugal", "Europe/Lisbon"}, 1299 {"ROC", "Asia/Taipei"}, 1300 {"ROK", "Asia/Seoul"}, 1301 {"Singapore", "Asia/Singapore"}, 1302 {"Turkey", "Europe/Istanbul"}, 1303 {"UCT", "Etc/GMT"}, 1304 {"US/Alaska", "America/Anchorage"}, 1305 {"US/Aleutian", "America/Adak"}, 1306 {"US/Arizona", "America/Phoenix"}, 1307 {"US/Central", "America/Chicago"}, 1308 {"US/East-Indiana", "America/Indiana/Indianapolis"}, 1309 {"US/Eastern", "America/New_York"}, 1310 {"US/Hawaii", "Pacific/Honolulu"}, 1311 {"US/Indiana-Starke", "America/Indiana/Knox"}, 1312 {"US/Michigan", "America/Detroit"}, 1313 {"US/Mountain", "America/Denver"}, 1314 {"US/Pacific", "America/Los_Angeles"}, 1315 {"US/Pacific-New", "America/Los_Angeles"}, 1316 {"US/Samoa", "Pacific/Pago_Pago"}, 1317 {"UTC", "Etc/GMT"}, 1318 {"Universal", "Etc/GMT"}, 1319 {"W-SU", "Europe/Moscow"}, 1320 {"Zulu", "Etc/GMT"}, 1321 /* Total: 113 */ 1322 1323 }; 1324 1325 TimeZone::EDisplayType styles[] = { TimeZone::SHORT, TimeZone::LONG }; 1326 UBool useDst[] = { FALSE, TRUE }; 1327 int32_t noLoc = uloc_countAvailable(); 1328 1329 int32_t i, j, k, loc; 1330 UnicodeString fromName, toName; 1331 TimeZone *from = NULL, *to = NULL; 1332 for(i = 0; i < (int32_t)(sizeof(kData)/sizeof(kData[0])); i++) { 1333 from = TimeZone::createTimeZone(kData[i].from); 1334 to = TimeZone::createTimeZone(kData[i].to); 1335 if(!from->hasSameRules(*to)) { 1336 errln("different at %i\n", i); 1337 } 1338 if(!quick) { 1339 for(loc = 0; loc < noLoc; loc++) { 1340 const char* locale = uloc_getAvailable(loc); 1341 for(j = 0; j < (int32_t)(sizeof(styles)/sizeof(styles[0])); j++) { 1342 for(k = 0; k < (int32_t)(sizeof(useDst)/sizeof(useDst[0])); k++) { 1343 fromName.remove(); 1344 toName.remove(); 1345 from->getDisplayName(useDst[k], styles[j],locale, fromName); 1346 to->getDisplayName(useDst[k], styles[j], locale, toName); 1347 if(fromName.compare(toName) != 0) { 1348 errln("Fail: Expected "+toName+" but got " + prettify(fromName) 1349 + " for locale: " + locale + " index: "+ loc 1350 + " to id "+ kData[i].to 1351 + " from id " + kData[i].from); 1352 } 1353 } 1354 } 1355 } 1356 } else { 1357 fromName.remove(); 1358 toName.remove(); 1359 from->getDisplayName(fromName); 1360 to->getDisplayName(toName); 1361 if(fromName.compare(toName) != 0) { 1362 errln("Fail: Expected "+toName+" but got " + fromName); 1363 } 1364 } 1365 delete from; 1366 delete to; 1367 } 1368 } 1369 1370 /** 1371 * Test the basic functionality of the getDisplayName() API. 1372 * 1373 * @bug 4112869 1374 * @bug 4028006 1375 * 1376 * See also API change request A41. 1377 * 1378 * 4/21/98 - make smarter, so the test works if the ext resources 1379 * are present or not. 1380 */ 1381 void 1382 TimeZoneTest::TestDisplayName() 1383 { 1384 UErrorCode status = U_ZERO_ERROR; 1385 int32_t i; 1386 TimeZone *zone = TimeZone::createTimeZone("PST"); 1387 UnicodeString name; 1388 zone->getDisplayName(Locale::getEnglish(), name); 1389 logln("PST->" + name); 1390 if (name.compare("Pacific Standard Time") != 0) 1391 dataerrln("Fail: Expected \"Pacific Standard Time\" but got " + name); 1392 1393 //***************************************************************** 1394 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES 1395 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES 1396 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES 1397 //***************************************************************** 1398 struct 1399 { 1400 UBool useDst; 1401 TimeZone::EDisplayType style; 1402 const char *expect; 1403 } kData[] = { 1404 {FALSE, TimeZone::SHORT, "PST"}, 1405 {TRUE, TimeZone::SHORT, "PDT"}, 1406 {FALSE, TimeZone::LONG, "Pacific Standard Time"}, 1407 {TRUE, TimeZone::LONG, "Pacific Daylight Time"}, 1408 1409 {FALSE, TimeZone::SHORT_GENERIC, "PT"}, 1410 {TRUE, TimeZone::SHORT_GENERIC, "PT"}, 1411 {FALSE, TimeZone::LONG_GENERIC, "Pacific Time"}, 1412 {TRUE, TimeZone::LONG_GENERIC, "Pacific Time"}, 1413 1414 {FALSE, TimeZone::SHORT_GMT, "-0800"}, 1415 {TRUE, TimeZone::SHORT_GMT, "-0700"}, 1416 {FALSE, TimeZone::LONG_GMT, "GMT-08:00"}, 1417 {TRUE, TimeZone::LONG_GMT, "GMT-07:00"}, 1418 1419 {FALSE, TimeZone::SHORT_COMMONLY_USED, "PST"}, 1420 {TRUE, TimeZone::SHORT_COMMONLY_USED, "PDT"}, 1421 {FALSE, TimeZone::GENERIC_LOCATION, "Los Angeles Time"}, 1422 {TRUE, TimeZone::GENERIC_LOCATION, "Los Angeles Time"}, 1423 1424 {FALSE, TimeZone::LONG, ""} 1425 }; 1426 1427 for (i=0; kData[i].expect[0] != '\0'; i++) 1428 { 1429 name.remove(); 1430 name = zone->getDisplayName(kData[i].useDst, 1431 kData[i].style, 1432 Locale::getEnglish(), name); 1433 if (name.compare(kData[i].expect) != 0) 1434 dataerrln("Fail: Expected " + UnicodeString(kData[i].expect) + "; got " + name); 1435 logln("PST [with options]->" + name); 1436 } 1437 for (i=0; kData[i].expect[0] != '\0'; i++) 1438 { 1439 name.remove(); 1440 name = zone->getDisplayName(kData[i].useDst, 1441 kData[i].style, name); 1442 if (name.compare(kData[i].expect) != 0) 1443 dataerrln("Fail: Expected " + UnicodeString(kData[i].expect) + "; got " + name); 1444 logln("PST [with options]->" + name); 1445 } 1446 1447 1448 // Make sure that we don't display the DST name by constructing a fake 1449 // PST zone that has DST all year long. 1450 SimpleTimeZone *zone2 = new SimpleTimeZone(0, "PST"); 1451 1452 zone2->setStartRule(UCAL_JANUARY, 1, 0, 0, status); 1453 zone2->setEndRule(UCAL_DECEMBER, 31, 0, 0, status); 1454 1455 UnicodeString inDaylight; 1456 if (zone2->inDaylightTime(UDate(0), status)) { 1457 inDaylight = UnicodeString("TRUE"); 1458 } else { 1459 inDaylight = UnicodeString("FALSE"); 1460 } 1461 logln(UnicodeString("Modified PST inDaylightTime->") + inDaylight ); 1462 if(U_FAILURE(status)) 1463 { 1464 dataerrln("Some sort of error..." + UnicodeString(u_errorName(status))); // REVISIT 1465 } 1466 name.remove(); 1467 name = zone2->getDisplayName(Locale::getEnglish(),name); 1468 logln("Modified PST->" + name); 1469 if (name.compare("Pacific Standard Time") != 0) 1470 dataerrln("Fail: Expected \"Pacific Standard Time\""); 1471 1472 // Make sure we get the default display format for Locales 1473 // with no display name data. 1474 Locale mt_MT("mt_MT"); 1475 name.remove(); 1476 name = zone->getDisplayName(mt_MT,name); 1477 //***************************************************************** 1478 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES 1479 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES 1480 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES 1481 //***************************************************************** 1482 logln("PST(mt_MT)->" + name); 1483 1484 // *** REVISIT SRL how in the world do I check this? looks java specific. 1485 // Now be smart -- check to see if zh resource is even present. 1486 // If not, we expect the en fallback behavior. 1487 ResourceBundle enRB(NULL, 1488 Locale::getEnglish(), status); 1489 if(U_FAILURE(status)) 1490 dataerrln("Couldn't get ResourceBundle for en - %s", u_errorName(status)); 1491 1492 ResourceBundle mtRB(NULL, 1493 mt_MT, status); 1494 //if(U_FAILURE(status)) 1495 // errln("Couldn't get ResourceBundle for mt_MT"); 1496 1497 UBool noZH = U_FAILURE(status); 1498 1499 if (noZH) { 1500 logln("Warning: Not testing the mt_MT behavior because resource is absent"); 1501 if (name != "Pacific Standard Time") 1502 dataerrln("Fail: Expected Pacific Standard Time"); 1503 } 1504 1505 1506 if (name.compare("GMT-08:00") && 1507 name.compare("GMT-8:00") && 1508 name.compare("GMT-0800") && 1509 name.compare("GMT-800")) { 1510 dataerrln(UnicodeString("Fail: Expected GMT-08:00 or something similar for PST in mt_MT but got ") + name ); 1511 dataerrln("************************************************************"); 1512 dataerrln("THE ABOVE FAILURE MAY JUST MEAN THE LOCALE DATA HAS CHANGED"); 1513 dataerrln("************************************************************"); 1514 } 1515 1516 // Now try a non-existent zone 1517 delete zone2; 1518 zone2 = new SimpleTimeZone(90*60*1000, "xyzzy"); 1519 name.remove(); 1520 name = zone2->getDisplayName(Locale::getEnglish(),name); 1521 logln("GMT+90min->" + name); 1522 if (name.compare("GMT+01:30") && 1523 name.compare("GMT+1:30") && 1524 name.compare("GMT+0130") && 1525 name.compare("GMT+130")) 1526 dataerrln("Fail: Expected GMT+01:30 or something similar"); 1527 name.truncate(0); 1528 zone2->getDisplayName(name); 1529 logln("GMT+90min->" + name); 1530 if (name.compare("GMT+01:30") && 1531 name.compare("GMT+1:30") && 1532 name.compare("GMT+0130") && 1533 name.compare("GMT+130")) 1534 dataerrln("Fail: Expected GMT+01:30 or something similar"); 1535 // clean up 1536 delete zone; 1537 delete zone2; 1538 } 1539 1540 /** 1541 * @bug 4107276 1542 */ 1543 void 1544 TimeZoneTest::TestDSTSavings() 1545 { 1546 UErrorCode status = U_ZERO_ERROR; 1547 // It might be better to find a way to integrate this test into the main TimeZone 1548 // tests above, but I don't have time to figure out how to do this (or if it's 1549 // even really a good idea). Let's consider that a future. --rtg 1/27/98 1550 SimpleTimeZone *tz = new SimpleTimeZone(-5 * U_MILLIS_PER_HOUR, "dstSavingsTest", 1551 UCAL_MARCH, 1, 0, 0, UCAL_SEPTEMBER, 1, 0, 0, 1552 (int32_t)(0.5 * U_MILLIS_PER_HOUR), status); 1553 if(U_FAILURE(status)) 1554 errln("couldn't create TimeZone"); 1555 1556 if (tz->getRawOffset() != -5 * U_MILLIS_PER_HOUR) 1557 errln(UnicodeString("Got back a raw offset of ") + (tz->getRawOffset() / U_MILLIS_PER_HOUR) + 1558 " hours instead of -5 hours."); 1559 if (!tz->useDaylightTime()) 1560 errln("Test time zone should use DST but claims it doesn't."); 1561 if (tz->getDSTSavings() != 0.5 * U_MILLIS_PER_HOUR) 1562 errln(UnicodeString("Set DST offset to 0.5 hour, but got back ") + (tz->getDSTSavings() / 1563 U_MILLIS_PER_HOUR) + " hours instead."); 1564 1565 int32_t offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JANUARY, 1, 1566 UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status); 1567 if (offset != -5 * U_MILLIS_PER_HOUR) 1568 errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ") 1569 + (offset / U_MILLIS_PER_HOUR) + " hours."); 1570 1571 offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JUNE, 1, UCAL_MONDAY, 1572 10 * U_MILLIS_PER_HOUR,status); 1573 if (offset != -4.5 * U_MILLIS_PER_HOUR) 1574 errln(UnicodeString("The offset for 10 AM, 6/1/98 should have been -4.5 hours, but we got ") 1575 + (offset / U_MILLIS_PER_HOUR) + " hours."); 1576 1577 tz->setDSTSavings(U_MILLIS_PER_HOUR, status); 1578 offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JANUARY, 1, 1579 UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status); 1580 if (offset != -5 * U_MILLIS_PER_HOUR) 1581 errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ") 1582 + (offset / U_MILLIS_PER_HOUR) + " hours."); 1583 1584 offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JUNE, 1, UCAL_MONDAY, 1585 10 * U_MILLIS_PER_HOUR,status); 1586 if (offset != -4 * U_MILLIS_PER_HOUR) 1587 errln(UnicodeString("The offset for 10 AM, 6/1/98 (with a 1-hour DST offset) should have been -4 hours, but we got ") 1588 + (offset / U_MILLIS_PER_HOUR) + " hours."); 1589 1590 delete tz; 1591 } 1592 1593 /** 1594 * @bug 4107570 1595 */ 1596 void 1597 TimeZoneTest::TestAlternateRules() 1598 { 1599 // Like TestDSTSavings, this test should probably be integrated somehow with the main 1600 // test at the top of this class, but I didn't have time to figure out how to do that. 1601 // --rtg 1/28/98 1602 1603 SimpleTimeZone tz(-5 * U_MILLIS_PER_HOUR, "alternateRuleTest"); 1604 1605 // test the day-of-month API 1606 UErrorCode status = U_ZERO_ERROR; 1607 tz.setStartRule(UCAL_MARCH, 10, 12 * U_MILLIS_PER_HOUR, status); 1608 if(U_FAILURE(status)) 1609 errln("tz.setStartRule failed"); 1610 tz.setEndRule(UCAL_OCTOBER, 20, 12 * U_MILLIS_PER_HOUR, status); 1611 if(U_FAILURE(status)) 1612 errln("tz.setStartRule failed"); 1613 1614 int32_t offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 5, 1615 UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status); 1616 if (offset != -5 * U_MILLIS_PER_HOUR) 1617 errln(UnicodeString("The offset for 10AM, 3/5/98 should have been -5 hours, but we got ") 1618 + (offset / U_MILLIS_PER_HOUR) + " hours."); 1619 1620 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 15, 1621 UCAL_SUNDAY, 10 * millisPerHour,status); 1622 if (offset != -4 * U_MILLIS_PER_HOUR) 1623 errln(UnicodeString("The offset for 10AM, 3/15/98 should have been -4 hours, but we got ") 1624 + (offset / U_MILLIS_PER_HOUR) + " hours."); 1625 1626 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 15, 1627 UCAL_THURSDAY, 10 * millisPerHour,status); 1628 if (offset != -4 * U_MILLIS_PER_HOUR) 1629 errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ") + (offset / U_MILLIS_PER_HOUR) + " hours."); 1630 1631 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 25, 1632 UCAL_SUNDAY, 10 * millisPerHour,status); 1633 if (offset != -5 * U_MILLIS_PER_HOUR) 1634 errln(UnicodeString("The offset for 10AM, 10/25/98 should have been -5 hours, but we got ") 1635 + (offset / U_MILLIS_PER_HOUR) + " hours."); 1636 1637 // test the day-of-week-after-day-in-month API 1638 tz.setStartRule(UCAL_MARCH, 10, UCAL_FRIDAY, 12 * millisPerHour, TRUE, status); 1639 if(U_FAILURE(status)) 1640 errln("tz.setStartRule failed"); 1641 tz.setEndRule(UCAL_OCTOBER, 20, UCAL_FRIDAY, 12 * millisPerHour, FALSE, status); 1642 if(U_FAILURE(status)) 1643 errln("tz.setStartRule failed"); 1644 1645 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 11, 1646 UCAL_WEDNESDAY, 10 * millisPerHour,status); 1647 if (offset != -5 * U_MILLIS_PER_HOUR) 1648 errln(UnicodeString("The offset for 10AM, 3/11/98 should have been -5 hours, but we got ") 1649 + (offset / U_MILLIS_PER_HOUR) + " hours."); 1650 1651 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 14, 1652 UCAL_SATURDAY, 10 * millisPerHour,status); 1653 if (offset != -4 * U_MILLIS_PER_HOUR) 1654 errln(UnicodeString("The offset for 10AM, 3/14/98 should have been -4 hours, but we got ") 1655 + (offset / U_MILLIS_PER_HOUR) + " hours."); 1656 1657 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 15, 1658 UCAL_THURSDAY, 10 * millisPerHour,status); 1659 if (offset != -4 * U_MILLIS_PER_HOUR) 1660 errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ") 1661 + (offset / U_MILLIS_PER_HOUR) + " hours."); 1662 1663 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 17, 1664 UCAL_SATURDAY, 10 * millisPerHour,status); 1665 if (offset != -5 * U_MILLIS_PER_HOUR) 1666 errln(UnicodeString("The offset for 10AM, 10/17/98 should have been -5 hours, but we got ") 1667 + (offset / U_MILLIS_PER_HOUR) + " hours."); 1668 } 1669 1670 void TimeZoneTest::TestFractionalDST() { 1671 const char* tzName = "Australia/Lord_Howe"; // 30 min offset 1672 TimeZone* tz_icu = TimeZone::createTimeZone(tzName); 1673 int dst_icu = tz_icu->getDSTSavings(); 1674 UnicodeString id; 1675 int32_t expected = 1800000; 1676 if (expected != dst_icu) { 1677 dataerrln(UnicodeString("java reports dst savings of ") + expected + 1678 " but icu reports " + dst_icu + 1679 " for tz " + tz_icu->getID(id)); 1680 } else { 1681 logln(UnicodeString("both java and icu report dst savings of ") + expected + " for tz " + tz_icu->getID(id)); 1682 } 1683 delete tz_icu; 1684 } 1685 1686 /** 1687 * Test country code support. Jitterbug 776. 1688 */ 1689 void TimeZoneTest::TestCountries() { 1690 // Make sure America/Los_Angeles is in the "US" group, and 1691 // Asia/Tokyo isn't. Vice versa for the "JP" group. 1692 UErrorCode ec = U_ZERO_ERROR; 1693 int32_t n; 1694 StringEnumeration* s = TimeZone::createEnumeration("US"); 1695 if (s == NULL) { 1696 dataerrln("Unable to create TimeZone enumeration for US"); 1697 return; 1698 } 1699 n = s->count(ec); 1700 UBool la = FALSE, tokyo = FALSE; 1701 UnicodeString laZone("America/Los_Angeles", ""); 1702 UnicodeString tokyoZone("Asia/Tokyo", ""); 1703 int32_t i; 1704 1705 if (s == NULL || n <= 0) { 1706 dataerrln("FAIL: TimeZone::createEnumeration() returned nothing"); 1707 return; 1708 } 1709 for (i=0; i<n; ++i) { 1710 const UnicodeString* id = s->snext(ec); 1711 if (*id == (laZone)) { 1712 la = TRUE; 1713 } 1714 if (*id == (tokyoZone)) { 1715 tokyo = TRUE; 1716 } 1717 } 1718 if (!la || tokyo) { 1719 errln("FAIL: " + laZone + " in US = " + la); 1720 errln("FAIL: " + tokyoZone + " in US = " + tokyo); 1721 } 1722 delete s; 1723 1724 s = TimeZone::createEnumeration("JP"); 1725 n = s->count(ec); 1726 la = FALSE; tokyo = FALSE; 1727 1728 for (i=0; i<n; ++i) { 1729 const UnicodeString* id = s->snext(ec); 1730 if (*id == (laZone)) { 1731 la = TRUE; 1732 } 1733 if (*id == (tokyoZone)) { 1734 tokyo = TRUE; 1735 } 1736 } 1737 if (la || !tokyo) { 1738 errln("FAIL: " + laZone + " in JP = " + la); 1739 errln("FAIL: " + tokyoZone + " in JP = " + tokyo); 1740 } 1741 StringEnumeration* s1 = TimeZone::createEnumeration("US"); 1742 StringEnumeration* s2 = TimeZone::createEnumeration("US"); 1743 for(i=0;i<n;++i){ 1744 const UnicodeString* id1 = s1->snext(ec); 1745 if(id1==NULL || U_FAILURE(ec)){ 1746 errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n,i); 1747 } 1748 TimeZone* tz1 = TimeZone::createTimeZone(*id1); 1749 for(int j=0; j<n;++j){ 1750 const UnicodeString* id2 = s2->snext(ec); 1751 if(id2==NULL || U_FAILURE(ec)){ 1752 errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n,i); 1753 } 1754 TimeZone* tz2 = TimeZone::createTimeZone(*id2); 1755 if(tz1->hasSameRules(*tz2)){ 1756 logln("ID1 : " + *id1+" == ID2 : " +*id2); 1757 } 1758 delete tz2; 1759 } 1760 delete tz1; 1761 } 1762 delete s1; 1763 delete s2; 1764 delete s; 1765 } 1766 1767 void TimeZoneTest::TestHistorical() { 1768 const int32_t H = U_MILLIS_PER_HOUR; 1769 struct { 1770 const char* id; 1771 int32_t time; // epoch seconds 1772 int32_t offset; // total offset (millis) 1773 } DATA[] = { 1774 // Add transition points (before/after) as desired to test historical 1775 // behavior. 1776 {"America/Los_Angeles", 638963999, -8*H}, // Sun Apr 01 01:59:59 GMT-08:00 1990 1777 {"America/Los_Angeles", 638964000, -7*H}, // Sun Apr 01 03:00:00 GMT-07:00 1990 1778 {"America/Los_Angeles", 657104399, -7*H}, // Sun Oct 28 01:59:59 GMT-07:00 1990 1779 {"America/Los_Angeles", 657104400, -8*H}, // Sun Oct 28 01:00:00 GMT-08:00 1990 1780 {"America/Goose_Bay", -116445601, -4*H}, // Sun Apr 24 01:59:59 GMT-04:00 1966 1781 {"America/Goose_Bay", -116445600, -3*H}, // Sun Apr 24 03:00:00 GMT-03:00 1966 1782 {"America/Goose_Bay", -100119601, -3*H}, // Sun Oct 30 01:59:59 GMT-03:00 1966 1783 {"America/Goose_Bay", -100119600, -4*H}, // Sun Oct 30 01:00:00 GMT-04:00 1966 1784 {"America/Goose_Bay", -84391201, -4*H}, // Sun Apr 30 01:59:59 GMT-04:00 1967 1785 {"America/Goose_Bay", -84391200, -3*H}, // Sun Apr 30 03:00:00 GMT-03:00 1967 1786 {"America/Goose_Bay", -68670001, -3*H}, // Sun Oct 29 01:59:59 GMT-03:00 1967 1787 {"America/Goose_Bay", -68670000, -4*H}, // Sun Oct 29 01:00:00 GMT-04:00 1967 1788 {0, 0, 0} 1789 }; 1790 1791 for (int32_t i=0; DATA[i].id!=0; ++i) { 1792 const char* id = DATA[i].id; 1793 TimeZone *tz = TimeZone::createTimeZone(id); 1794 UnicodeString s; 1795 if (tz == 0) { 1796 errln("FAIL: Cannot create %s", id); 1797 } else if (tz->getID(s) != UnicodeString(id)) { 1798 dataerrln((UnicodeString)"FAIL: createTimeZone(" + id + ") => " + s); 1799 } else { 1800 UErrorCode ec = U_ZERO_ERROR; 1801 int32_t raw, dst; 1802 UDate when = (double) DATA[i].time * U_MILLIS_PER_SECOND; 1803 tz->getOffset(when, FALSE, raw, dst, ec); 1804 if (U_FAILURE(ec)) { 1805 errln("FAIL: getOffset"); 1806 } else if ((raw+dst) != DATA[i].offset) { 1807 errln((UnicodeString)"FAIL: " + DATA[i].id + ".getOffset(" + 1808 //when + " = " + 1809 dateToString(when) + ") => " + 1810 raw + ", " + dst); 1811 } else { 1812 logln((UnicodeString)"Ok: " + DATA[i].id + ".getOffset(" + 1813 //when + " = " + 1814 dateToString(when) + ") => " + 1815 raw + ", " + dst); 1816 } 1817 } 1818 delete tz; 1819 } 1820 } 1821 1822 void TimeZoneTest::TestEquivalentIDs() { 1823 int32_t n = TimeZone::countEquivalentIDs("PST"); 1824 if (n < 2) { 1825 dataerrln((UnicodeString)"FAIL: countEquivalentIDs(PST) = " + n); 1826 } else { 1827 UBool sawLA = FALSE; 1828 for (int32_t i=0; i<n; ++i) { 1829 UnicodeString id = TimeZone::getEquivalentID("PST", i); 1830 logln((UnicodeString)"" + i + " : " + id); 1831 if (id == UnicodeString("America/Los_Angeles")) { 1832 sawLA = TRUE; 1833 } 1834 } 1835 if (!sawLA) { 1836 errln("FAIL: America/Los_Angeles should be in the list"); 1837 } 1838 } 1839 } 1840 1841 // Test that a transition at the end of February is handled correctly. 1842 void TimeZoneTest::TestFebruary() { 1843 UErrorCode status = U_ZERO_ERROR; 1844 1845 // Time zone with daylight savings time from the first Sunday in November 1846 // to the last Sunday in February. 1847 // Similar to the new rule for Brazil (Sao Paulo) in tzdata2006n. 1848 // 1849 // Note: In tzdata2007h, the rule had changed, so no actual zones uses 1850 // lastSun in Feb anymore. 1851 SimpleTimeZone tz1(-3 * U_MILLIS_PER_HOUR, // raw offset: 3h before (west of) GMT 1852 UNICODE_STRING("nov-feb", 7), 1853 UCAL_NOVEMBER, 1, UCAL_SUNDAY, // start: November, first, Sunday 1854 0, // midnight wall time 1855 UCAL_FEBRUARY, -1, UCAL_SUNDAY, // end: February, last, Sunday 1856 0, // midnight wall time 1857 status); 1858 if (U_FAILURE(status)) { 1859 errln("Unable to create the SimpleTimeZone(nov-feb): %s", u_errorName(status)); 1860 return; 1861 } 1862 1863 // Now hardcode the same rules as for Brazil in tzdata 2006n, so that 1864 // we cover the intended code even when in the future zoneinfo hardcodes 1865 // these transition dates. 1866 SimpleTimeZone tz2(-3 * U_MILLIS_PER_HOUR, // raw offset: 3h before (west of) GMT 1867 UNICODE_STRING("nov-feb2", 8), 1868 UCAL_NOVEMBER, 1, -UCAL_SUNDAY, // start: November, 1 or after, Sunday 1869 0, // midnight wall time 1870 UCAL_FEBRUARY, -29, -UCAL_SUNDAY,// end: February, 29 or before, Sunday 1871 0, // midnight wall time 1872 status); 1873 if (U_FAILURE(status)) { 1874 errln("Unable to create the SimpleTimeZone(nov-feb2): %s", u_errorName(status)); 1875 return; 1876 } 1877 1878 // Gregorian calendar with the UTC time zone for getting sample test date/times. 1879 GregorianCalendar gc(*TimeZone::getGMT(), status); 1880 if (U_FAILURE(status)) { 1881 dataerrln("Unable to create the UTC calendar: %s", u_errorName(status)); 1882 return; 1883 } 1884 1885 struct { 1886 // UTC time. 1887 int32_t year, month, day, hour, minute, second; 1888 // Expected time zone offset in hours after GMT (negative=before GMT). 1889 int32_t offsetHours; 1890 } data[] = { 1891 { 2006, UCAL_NOVEMBER, 5, 02, 59, 59, -3 }, 1892 { 2006, UCAL_NOVEMBER, 5, 03, 00, 00, -2 }, 1893 { 2007, UCAL_FEBRUARY, 25, 01, 59, 59, -2 }, 1894 { 2007, UCAL_FEBRUARY, 25, 02, 00, 00, -3 }, 1895 1896 { 2007, UCAL_NOVEMBER, 4, 02, 59, 59, -3 }, 1897 { 2007, UCAL_NOVEMBER, 4, 03, 00, 00, -2 }, 1898 { 2008, UCAL_FEBRUARY, 24, 01, 59, 59, -2 }, 1899 { 2008, UCAL_FEBRUARY, 24, 02, 00, 00, -3 }, 1900 1901 { 2008, UCAL_NOVEMBER, 2, 02, 59, 59, -3 }, 1902 { 2008, UCAL_NOVEMBER, 2, 03, 00, 00, -2 }, 1903 { 2009, UCAL_FEBRUARY, 22, 01, 59, 59, -2 }, 1904 { 2009, UCAL_FEBRUARY, 22, 02, 00, 00, -3 }, 1905 1906 { 2009, UCAL_NOVEMBER, 1, 02, 59, 59, -3 }, 1907 { 2009, UCAL_NOVEMBER, 1, 03, 00, 00, -2 }, 1908 { 2010, UCAL_FEBRUARY, 28, 01, 59, 59, -2 }, 1909 { 2010, UCAL_FEBRUARY, 28, 02, 00, 00, -3 } 1910 }; 1911 1912 TimeZone *timezones[] = { &tz1, &tz2 }; 1913 1914 TimeZone *tz; 1915 UDate dt; 1916 int32_t t, i, raw, dst; 1917 for (t = 0; t < LENGTHOF(timezones); ++t) { 1918 tz = timezones[t]; 1919 for (i = 0; i < LENGTHOF(data); ++i) { 1920 gc.set(data[i].year, data[i].month, data[i].day, 1921 data[i].hour, data[i].minute, data[i].second); 1922 dt = gc.getTime(status); 1923 if (U_FAILURE(status)) { 1924 errln("test case %d.%d: bad date/time %04d-%02d-%02d %02d:%02d:%02d", 1925 t, i, 1926 data[i].year, data[i].month + 1, data[i].day, 1927 data[i].hour, data[i].minute, data[i].second); 1928 status = U_ZERO_ERROR; 1929 continue; 1930 } 1931 tz->getOffset(dt, FALSE, raw, dst, status); 1932 if (U_FAILURE(status)) { 1933 errln("test case %d.%d: tz.getOffset(%04d-%02d-%02d %02d:%02d:%02d) fails: %s", 1934 t, i, 1935 data[i].year, data[i].month + 1, data[i].day, 1936 data[i].hour, data[i].minute, data[i].second, 1937 u_errorName(status)); 1938 status = U_ZERO_ERROR; 1939 } else if ((raw + dst) != data[i].offsetHours * U_MILLIS_PER_HOUR) { 1940 errln("test case %d.%d: tz.getOffset(%04d-%02d-%02d %02d:%02d:%02d) returns %d+%d != %d", 1941 t, i, 1942 data[i].year, data[i].month + 1, data[i].day, 1943 data[i].hour, data[i].minute, data[i].second, 1944 raw, dst, data[i].offsetHours * U_MILLIS_PER_HOUR); 1945 } 1946 } 1947 } 1948 } 1949 void TimeZoneTest::TestCanonicalID() { 1950 1951 // Some canonical IDs in CLDR are defined as "Link" 1952 // in Olson tzdata. 1953 static const struct { 1954 const char *alias; 1955 const char *zone; 1956 } excluded1[] = { 1957 {"America/Shiprock", "America/Denver"}, // America/Shiprock is defined as a Link to America/Denver in tzdata 1958 {"America/Marigot", "America/Guadeloupe"}, 1959 {"America/St_Barthelemy", "America/Guadeloupe"}, 1960 {"America/Lower_Princes", "America/Curacao"}, 1961 {"America/Kralendijk", "America/Curacao"}, 1962 {"Antarctica/South_Pole", "Antarctica/McMurdo"}, 1963 {"Atlantic/Jan_Mayen", "Europe/Oslo"}, 1964 {"Arctic/Longyearbyen", "Europe/Oslo"}, 1965 {"Europe/Busingen", "Europe/Zurich"}, 1966 {"Europe/Guernsey", "Europe/London"}, 1967 {"Europe/Isle_of_Man", "Europe/London"}, 1968 {"Europe/Jersey", "Europe/London"}, 1969 {"Europe/Ljubljana", "Europe/Belgrade"}, 1970 {"Europe/Podgorica", "Europe/Belgrade"}, 1971 {"Europe/Sarajevo", "Europe/Belgrade"}, 1972 {"Europe/Skopje", "Europe/Belgrade"}, 1973 {"Europe/Zagreb", "Europe/Belgrade"}, 1974 {"Europe/Bratislava", "Europe/Prague"}, 1975 {"Europe/Mariehamn", "Europe/Helsinki"}, 1976 {"Europe/San_Marino", "Europe/Rome"}, 1977 {"Europe/Vatican", "Europe/Rome"}, 1978 {0, 0} 1979 }; 1980 1981 // Following IDs are aliases of Etc/GMT in CLDR, 1982 // but Olson tzdata has 3 independent definitions 1983 // for Etc/GMT, Etc/UTC, Etc/UCT. 1984 // Until we merge them into one equivalent group 1985 // in zoneinfo.res, we exclude them in the test 1986 // below. 1987 static const char* excluded2[] = { 1988 "Etc/UCT", "UCT", 1989 "Etc/UTC", "UTC", 1990 "Etc/Universal", "Universal", 1991 "Etc/Zulu", "Zulu", 0 1992 }; 1993 1994 // Walk through equivalency groups 1995 UErrorCode ec = U_ZERO_ERROR; 1996 int32_t s_length, i, j, k; 1997 StringEnumeration* s = TimeZone::createEnumeration(); 1998 if (s == NULL) { 1999 dataerrln("Unable to create TimeZone enumeration"); 2000 return; 2001 } 2002 UnicodeString canonicalID, tmpCanonical; 2003 s_length = s->count(ec); 2004 for (i = 0; i < s_length;++i) { 2005 const UnicodeString *tzid = s->snext(ec); 2006 int32_t nEquiv = TimeZone::countEquivalentIDs(*tzid); 2007 if (nEquiv == 0) { 2008 continue; 2009 } 2010 UBool bFoundCanonical = FALSE; 2011 // Make sure getCanonicalID returns the exact same result 2012 // for all entries within a same equivalency group with some 2013 // exceptions listed in exluded1. 2014 // Also, one of them must be canonical id. 2015 for (j = 0; j < nEquiv; j++) { 2016 UnicodeString tmp = TimeZone::getEquivalentID(*tzid, j); 2017 TimeZone::getCanonicalID(tmp, tmpCanonical, ec); 2018 if (U_FAILURE(ec)) { 2019 errln((UnicodeString)"FAIL: getCanonicalID(" + tmp + ") failed."); 2020 ec = U_ZERO_ERROR; 2021 continue; 2022 } 2023 // Some exceptional cases 2024 for (k = 0; excluded1[k].alias != 0; k++) { 2025 if (tmpCanonical == excluded1[k].alias) { 2026 tmpCanonical = excluded1[k].zone; 2027 break; 2028 } 2029 } 2030 if (j == 0) { 2031 canonicalID = tmpCanonical; 2032 } else if (canonicalID != tmpCanonical) { 2033 errln("FAIL: getCanonicalID(" + tmp + ") returned " + tmpCanonical + " expected:" + canonicalID); 2034 } 2035 2036 if (canonicalID == tmp) { 2037 bFoundCanonical = TRUE; 2038 } 2039 } 2040 // At least one ID in an equvalency group must match the 2041 // canonicalID 2042 if (bFoundCanonical == FALSE) { 2043 // test exclusion because of differences between Olson tzdata and CLDR 2044 UBool isExcluded = FALSE; 2045 for (k = 0; excluded2[k] != 0; k++) { 2046 if (*tzid == UnicodeString(excluded2[k])) { 2047 isExcluded = TRUE; 2048 break; 2049 } 2050 } 2051 if (isExcluded) { 2052 continue; 2053 } 2054 errln((UnicodeString)"FAIL: No timezone ids match the canonical ID " + canonicalID); 2055 } 2056 } 2057 delete s; 2058 2059 // Testing some special cases 2060 static const struct { 2061 const char *id; 2062 const char *expected; 2063 UBool isSystem; 2064 } data[] = { 2065 {"GMT-03", "GMT-03:00", FALSE}, 2066 {"GMT+4", "GMT+04:00", FALSE}, 2067 {"GMT-055", "GMT-00:55", FALSE}, 2068 {"GMT+430", "GMT+04:30", FALSE}, 2069 {"GMT-12:15", "GMT-12:15", FALSE}, 2070 {"GMT-091015", "GMT-09:10:15", FALSE}, 2071 {"GMT+1:90", 0, FALSE}, 2072 {"America/Argentina/Buenos_Aires", "America/Buenos_Aires", TRUE}, 2073 {"Etc/Unknown", "Etc/Unknown", FALSE}, 2074 {"bogus", 0, FALSE}, 2075 {"", 0, FALSE}, 2076 {"America/Marigot", "America/Marigot", TRUE}, // Olson link, but CLDR canonical (#8953) 2077 {"Europe/Bratislava", "Europe/Bratislava", TRUE}, // Same as above 2078 {0, 0, FALSE} 2079 }; 2080 2081 UBool isSystemID; 2082 for (i = 0; data[i].id != 0; i++) { 2083 TimeZone::getCanonicalID(UnicodeString(data[i].id), canonicalID, isSystemID, ec); 2084 if (U_FAILURE(ec)) { 2085 if (ec != U_ILLEGAL_ARGUMENT_ERROR || data[i].expected != 0) { 2086 errln((UnicodeString)"FAIL: getCanonicalID(\"" + data[i].id 2087 + "\") returned status U_ILLEGAL_ARGUMENT_ERROR"); 2088 } 2089 ec = U_ZERO_ERROR; 2090 continue; 2091 } 2092 if (canonicalID != data[i].expected) { 2093 dataerrln((UnicodeString)"FAIL: getCanonicalID(\"" + data[i].id 2094 + "\") returned " + canonicalID + " - expected: " + data[i].expected); 2095 } 2096 if (isSystemID != data[i].isSystem) { 2097 dataerrln((UnicodeString)"FAIL: getCanonicalID(\"" + data[i].id 2098 + "\") set " + isSystemID + " to isSystemID"); 2099 } 2100 } 2101 } 2102 2103 // 2104 // Test Display Names, choosing zones and lcoales where there are multiple 2105 // meta-zones defined. 2106 // 2107 static struct { 2108 const char *zoneName; 2109 const char *localeName; 2110 UBool summerTime; 2111 TimeZone::EDisplayType style; 2112 const char *expectedDisplayName; } 2113 zoneDisplayTestData [] = { 2114 // zone id locale summer format expected display name 2115 {"Europe/London", "en", FALSE, TimeZone::SHORT, "GMT"}, 2116 {"Europe/London", "en", FALSE, TimeZone::LONG, "Greenwich Mean Time"}, 2117 {"Europe/London", "en", TRUE, TimeZone::SHORT, "GMT+1" /*"BST"*/}, 2118 {"Europe/London", "en", TRUE, TimeZone::LONG, "British Summer Time"}, 2119 2120 {"America/Anchorage", "en", FALSE, TimeZone::SHORT, "AKST"}, 2121 {"America/Anchorage", "en", FALSE, TimeZone::LONG, "Alaska Standard Time"}, 2122 {"America/Anchorage", "en", TRUE, TimeZone::SHORT, "AKDT"}, 2123 {"America/Anchorage", "en", TRUE, TimeZone::LONG, "Alaska Daylight Time"}, 2124 2125 // Southern Hemisphere, all data from meta:Australia_Western 2126 {"Australia/Perth", "en", FALSE, TimeZone::SHORT, "GMT+8"/*"AWST"*/}, 2127 {"Australia/Perth", "en", FALSE, TimeZone::LONG, "Australian Western Standard Time"}, 2128 // Note: Perth does not observe DST currently. When display name is missing, 2129 // the localized GMT format with the current offset is used even daylight name was 2130 // requested. See #9350. 2131 {"Australia/Perth", "en", TRUE, TimeZone::SHORT, "GMT+8"/*"AWDT"*/}, 2132 {"Australia/Perth", "en", TRUE, TimeZone::LONG, "Australian Western Daylight Time"}, 2133 2134 {"America/Sao_Paulo", "en", FALSE, TimeZone::SHORT, "GMT-3"/*"BRT"*/}, 2135 {"America/Sao_Paulo", "en", FALSE, TimeZone::LONG, "Brasilia Standard Time"}, 2136 {"America/Sao_Paulo", "en", TRUE, TimeZone::SHORT, "GMT-2"/*"BRST"*/}, 2137 {"America/Sao_Paulo", "en", TRUE, TimeZone::LONG, "Brasilia Summer Time"}, 2138 2139 // No Summer Time, but had it before 1983. 2140 {"Pacific/Honolulu", "en", FALSE, TimeZone::SHORT, "HST"}, 2141 {"Pacific/Honolulu", "en", FALSE, TimeZone::LONG, "Hawaii-Aleutian Standard Time"}, 2142 {"Pacific/Honolulu", "en", TRUE, TimeZone::SHORT, "HDT"}, 2143 {"Pacific/Honolulu", "en", TRUE, TimeZone::LONG, "Hawaii-Aleutian Daylight Time"}, 2144 2145 // Northern, has Summer, not commonly used. 2146 {"Europe/Helsinki", "en", FALSE, TimeZone::SHORT, "GMT+2"/*"EET"*/}, 2147 {"Europe/Helsinki", "en", FALSE, TimeZone::LONG, "Eastern European Standard Time"}, 2148 {"Europe/Helsinki", "en", TRUE, TimeZone::SHORT, "GMT+3"/*"EEST"*/}, 2149 {"Europe/Helsinki", "en", TRUE, TimeZone::LONG, "Eastern European Summer Time"}, 2150 2151 // Repeating the test data for DST. The test data below trigger the problem reported 2152 // by Ticket#6644 2153 {"Europe/London", "en", TRUE, TimeZone::SHORT, "GMT+1" /*"BST"*/}, 2154 {"Europe/London", "en", TRUE, TimeZone::LONG, "British Summer Time"}, 2155 2156 {NULL, NULL, FALSE, TimeZone::SHORT, NULL} // NULL values terminate list 2157 }; 2158 2159 void TimeZoneTest::TestDisplayNamesMeta() { 2160 UErrorCode status = U_ZERO_ERROR; 2161 GregorianCalendar cal(*TimeZone::getGMT(), status); 2162 if (failure(status, "GregorianCalendar", TRUE)) return; 2163 2164 UBool sawAnError = FALSE; 2165 for (int testNum = 0; zoneDisplayTestData[testNum].zoneName != NULL; testNum++) { 2166 Locale locale = Locale::createFromName(zoneDisplayTestData[testNum].localeName); 2167 TimeZone *zone = TimeZone::createTimeZone(zoneDisplayTestData[testNum].zoneName); 2168 UnicodeString displayName; 2169 zone->getDisplayName(zoneDisplayTestData[testNum].summerTime, 2170 zoneDisplayTestData[testNum].style, 2171 locale, 2172 displayName); 2173 if (displayName != zoneDisplayTestData[testNum].expectedDisplayName) { 2174 char name[100]; 2175 UErrorCode status = U_ZERO_ERROR; 2176 displayName.extract(name, 100, NULL, status); 2177 if (isDevelopmentBuild) { 2178 sawAnError = TRUE; 2179 dataerrln("Incorrect time zone display name. zone = \"%s\",\n" 2180 " locale = \"%s\", style = %s, Summertime = %d\n" 2181 " Expected \"%s\", " 2182 " Got \"%s\"\n Error: %s", zoneDisplayTestData[testNum].zoneName, 2183 zoneDisplayTestData[testNum].localeName, 2184 zoneDisplayTestData[testNum].style==TimeZone::SHORT ? 2185 "SHORT" : "LONG", 2186 zoneDisplayTestData[testNum].summerTime, 2187 zoneDisplayTestData[testNum].expectedDisplayName, 2188 name, 2189 u_errorName(status)); 2190 } else { 2191 logln("Incorrect time zone display name. zone = \"%s\",\n" 2192 " locale = \"%s\", style = %s, Summertime = %d\n" 2193 " Expected \"%s\", " 2194 " Got \"%s\"\n", zoneDisplayTestData[testNum].zoneName, 2195 zoneDisplayTestData[testNum].localeName, 2196 zoneDisplayTestData[testNum].style==TimeZone::SHORT ? 2197 "SHORT" : "LONG", 2198 zoneDisplayTestData[testNum].summerTime, 2199 zoneDisplayTestData[testNum].expectedDisplayName, 2200 name); 2201 } 2202 } 2203 delete zone; 2204 } 2205 if (sawAnError) { 2206 dataerrln("***Note: Errors could be the result of changes to zoneStrings locale data"); 2207 } 2208 } 2209 2210 void TimeZoneTest::TestGetRegion() 2211 { 2212 static const struct { 2213 const char *id; 2214 const char *region; 2215 } data[] = { 2216 {"America/Los_Angeles", "US"}, 2217 {"America/Indianapolis", "US"}, // CLDR canonical, Olson backward 2218 {"America/Indiana/Indianapolis", "US"}, // CLDR alias 2219 {"Mexico/General", "MX"}, // Link America/Mexico_City, Olson backward 2220 {"Etc/UTC", "001"}, 2221 {"EST5EDT", "001"}, 2222 {"PST", "US"}, // Link America/Los_Angeles 2223 {"Europe/Helsinki", "FI"}, 2224 {"Europe/Mariehamn", "AX"}, // Link Europe/Helsinki, but in zone.tab 2225 {"Asia/Riyadh", "SA"}, 2226 {"Asia/Riyadh87", "001"}, // this should be "SA" actually, but not in zone.tab 2227 {"Etc/Unknown", 0}, // CLDR canonical, but not a sysmte zone ID 2228 {"bogus", 0}, // bogus 2229 {"GMT+08:00", 0}, // a custom ID, not a system zone ID 2230 {0, 0} 2231 }; 2232 2233 int32_t i; 2234 char region[4]; 2235 UErrorCode sts; 2236 for (i = 0; data[i].id; i++) { 2237 sts = U_ZERO_ERROR; 2238 TimeZone::getRegion(data[i].id, region, sizeof(region), sts); 2239 if (U_SUCCESS(sts)) { 2240 if (data[i].region == 0) { 2241 errln((UnicodeString)"Fail: getRegion(\"" + data[i].id + "\") returns " 2242 + region + " [expected: U_ILLEGAL_ARGUMENT_ERROR]"); 2243 } else if (uprv_strcmp(region, data[i].region) != 0) { 2244 errln((UnicodeString)"Fail: getRegion(\"" + data[i].id + "\") returns " 2245 + region + " [expected: " + data[i].region + "]"); 2246 } 2247 } else if (sts == U_ILLEGAL_ARGUMENT_ERROR) { 2248 if (data[i].region != 0) { 2249 dataerrln((UnicodeString)"Fail: getRegion(\"" + data[i].id 2250 + "\") returns error status U_ILLEGAL_ARGUMENT_ERROR [expected: " 2251 + data[i].region + "]"); 2252 } 2253 } else { 2254 errln((UnicodeString)"Fail: getRegion(\"" + data[i].id 2255 + "\") returns an unexpected error status"); 2256 } 2257 } 2258 2259 // Extra test cases for short buffer 2260 int32_t len; 2261 char region2[2]; 2262 sts = U_ZERO_ERROR; 2263 2264 len = TimeZone::getRegion("America/New_York", region2, sizeof(region2), sts); 2265 if (sts == U_ILLEGAL_ARGUMENT_ERROR) { 2266 dataerrln("Error calling TimeZone::getRegion"); 2267 } else { 2268 if (sts != U_STRING_NOT_TERMINATED_WARNING) { 2269 errln("Expected U_STRING_NOT_TERMINATED_WARNING"); 2270 } 2271 if (len != 2) { // length of "US" 2272 errln("Incorrect result length"); 2273 } 2274 if (uprv_strncmp(region2, "US", 2) != 0) { 2275 errln("Incorrect result"); 2276 } 2277 } 2278 2279 char region1[1]; 2280 sts = U_ZERO_ERROR; 2281 2282 len = TimeZone::getRegion("America/Chicago", region1, sizeof(region1), sts); 2283 if (sts == U_ILLEGAL_ARGUMENT_ERROR) { 2284 dataerrln("Error calling TimeZone::getRegion"); 2285 } else { 2286 if (sts != U_BUFFER_OVERFLOW_ERROR) { 2287 errln("Expected U_BUFFER_OVERFLOW_ERROR"); 2288 } 2289 if (len != 2) { // length of "US" 2290 errln("Incorrect result length"); 2291 } 2292 } 2293 } 2294 2295 void TimeZoneTest::TestGetUnknown() { 2296 const TimeZone &unknown = TimeZone::getUnknown(); 2297 UnicodeString expectedID = UNICODE_STRING_SIMPLE("Etc/Unknown"); 2298 UnicodeString id; 2299 assertEquals("getUnknown() wrong ID", expectedID, unknown.getID(id)); 2300 assertTrue("getUnknown() wrong offset", 0 == unknown.getRawOffset()); 2301 assertFalse("getUnknown() uses DST", unknown.useDaylightTime()); 2302 } 2303 2304 #endif /* #if !UCONFIG_NO_FORMATTING */ 2305