]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/tztest.cpp
ICU-8.11.4.tar.gz
[apple/icu.git] / icuSources / test / intltest / tztest.cpp
1 /***********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2006, 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 "tztest.h"
18 #include "cmemory.h"
19 #include "putilimp.h"
20
21 #define CASE(id,test) case id: \
22 name = #test; \
23 if (exec) { \
24 logln(#test "---"); logln(""); \
25 test(); \
26 } \
27 break
28
29 // *****************************************************************************
30 // class TimeZoneTest
31 // *****************************************************************************
32
33 void TimeZoneTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
34 {
35 if (exec) logln("TestSuite TestTimeZone");
36 switch (index) {
37 CASE(0, TestPRTOffset);
38 CASE(1, TestVariousAPI518);
39 CASE(2, TestGetAvailableIDs913);
40 CASE(3, TestGenericAPI);
41 CASE(4, TestRuleAPI);
42 CASE(5, TestShortZoneIDs);
43 CASE(6, TestCustomParse);
44 CASE(7, TestDisplayName);
45 CASE(8, TestDSTSavings);
46 CASE(9, TestAlternateRules);
47 CASE(10,TestCountries);
48 CASE(11,TestHistorical);
49 CASE(12,TestEquivalentIDs);
50 CASE(13, TestAliasedNames);
51 CASE(14, TestFractionalDST);
52 default: name = ""; break;
53 }
54 }
55
56 const int32_t TimeZoneTest::millisPerHour = 3600000;
57
58 // ---------------------------------------------------------------------------------
59
60 /**
61 * Generic API testing for API coverage.
62 */
63 void
64 TimeZoneTest::TestGenericAPI()
65 {
66 UnicodeString id("NewGMT");
67 int32_t offset = 12345;
68
69 SimpleTimeZone *zone = new SimpleTimeZone(offset, id);
70 if (zone->useDaylightTime()) errln("FAIL: useDaylightTime should return FALSE");
71
72 TimeZone* zoneclone = zone->clone();
73 if (!(*zoneclone == *zone)) errln("FAIL: clone or operator== failed");
74 zoneclone->setID("abc");
75 if (!(*zoneclone != *zone)) errln("FAIL: clone or operator!= failed");
76 delete zoneclone;
77
78 zoneclone = zone->clone();
79 if (!(*zoneclone == *zone)) errln("FAIL: clone or operator== failed");
80 zoneclone->setRawOffset(45678);
81 if (!(*zoneclone != *zone)) errln("FAIL: clone or operator!= failed");
82
83 SimpleTimeZone copy(*zone);
84 if (!(copy == *zone)) errln("FAIL: copy constructor or operator== failed");
85 copy = *(SimpleTimeZone*)zoneclone;
86 if (!(copy == *zoneclone)) errln("FAIL: assignment operator or operator== failed");
87
88 TimeZone* saveDefault = TimeZone::createDefault();
89 logln((UnicodeString)"TimeZone::createDefault() => " + saveDefault->getID(id));
90 //TimeZone* pstZone = TimeZone::createTimeZone("PST");
91
92 logln("call uprv_timezone() which uses the host");
93 logln("to get the difference in seconds between coordinated universal");
94 logln("time and local time. E.g., -28,800 for PST (GMT-8hrs)");
95
96 int32_t tzoffset = uprv_timezone();
97 logln(UnicodeString("Value returned from uprv_timezone = ") + tzoffset);
98 // Invert sign because UNIX semantics are backwards
99 if (tzoffset < 0)
100 tzoffset = -tzoffset;
101 // --- The following test would fail outside PST now that
102 // --- PST is generally set to be default timezone in format tests
103 //if ((*saveDefault == *pstZone) && (tzoffset != 28800)) {
104 // errln("FAIL: t_timezone may be incorrect. It is not 28800");
105 //}
106
107 if (tzoffset != 28800) {
108 logln("***** WARNING: If testing in the PST timezone, uprv_timezone should return 28800! *****");
109 }
110 if ((tzoffset % 1800 != 0)) {
111 errln("FAIL: t_timezone may be incorrect. It is not a multiple of 30min. It is %d", tzoffset);
112 }
113
114 TimeZone::adoptDefault(zone);
115 TimeZone* defaultzone = TimeZone::createDefault();
116 if (defaultzone == zone ||
117 !(*defaultzone == *zone))
118 errln("FAIL: createDefault failed");
119 TimeZone::adoptDefault(saveDefault);
120 delete defaultzone;
121 delete zoneclone;
122 //delete pstZone;
123 }
124
125 // ---------------------------------------------------------------------------------
126
127 /**
128 * Test the setStartRule/setEndRule API calls.
129 */
130 void
131 TimeZoneTest::TestRuleAPI()
132 {
133 UErrorCode status = U_ZERO_ERROR;
134
135 UDate offset = 60*60*1000*1.75; // Pick a weird offset
136 SimpleTimeZone *zone = new SimpleTimeZone((int32_t)offset, "TestZone");
137 if (zone->useDaylightTime()) errln("FAIL: useDaylightTime should return FALSE");
138
139 // Establish our expected transition times. Do this with a non-DST
140 // calendar with the (above) declared local offset.
141 GregorianCalendar *gc = new GregorianCalendar(*zone, status);
142 if (failure(status, "new GregorianCalendar")) return;
143 gc->clear();
144 gc->set(1990, UCAL_MARCH, 1);
145 UDate marchOneStd = gc->getTime(status); // Local Std time midnight
146 gc->clear();
147 gc->set(1990, UCAL_JULY, 1);
148 UDate julyOneStd = gc->getTime(status); // Local Std time midnight
149 if (failure(status, "GregorianCalendar::getTime")) return;
150
151 // Starting and ending hours, WALL TIME
152 int32_t startHour = (int32_t)(2.25 * 3600000);
153 int32_t endHour = (int32_t)(3.5 * 3600000);
154
155 zone->setStartRule(UCAL_MARCH, 1, 0, startHour, status);
156 zone->setEndRule (UCAL_JULY, 1, 0, endHour, status);
157
158 delete gc;
159 gc = new GregorianCalendar(*zone, status);
160 if (failure(status, "new GregorianCalendar")) return;
161
162 UDate marchOne = marchOneStd + startHour;
163 UDate julyOne = julyOneStd + endHour - 3600000; // Adjust from wall to Std time
164
165 UDate expMarchOne = 636251400000.0;
166 if (marchOne != expMarchOne)
167 {
168 errln((UnicodeString)"FAIL: Expected start computed as " + marchOne +
169 " = " + dateToString(marchOne));
170 logln((UnicodeString)" Should be " + expMarchOne +
171 " = " + dateToString(expMarchOne));
172 }
173
174 UDate expJulyOne = 646793100000.0;
175 if (julyOne != expJulyOne)
176 {
177 errln((UnicodeString)"FAIL: Expected start computed as " + julyOne +
178 " = " + dateToString(julyOne));
179 logln((UnicodeString)" Should be " + expJulyOne +
180 " = " + dateToString(expJulyOne));
181 }
182
183 testUsingBinarySearch(*zone, date(90, UCAL_JANUARY, 1), date(90, UCAL_JUNE, 15), marchOne);
184 testUsingBinarySearch(*zone, date(90, UCAL_JUNE, 1), date(90, UCAL_DECEMBER, 31), julyOne);
185
186 if (zone->inDaylightTime(marchOne - 1000, status) ||
187 !zone->inDaylightTime(marchOne, status))
188 errln("FAIL: Start rule broken");
189 if (!zone->inDaylightTime(julyOne - 1000, status) ||
190 zone->inDaylightTime(julyOne, status))
191 errln("FAIL: End rule broken");
192
193 zone->setStartYear(1991);
194 if (zone->inDaylightTime(marchOne, status) ||
195 zone->inDaylightTime(julyOne - 1000, status))
196 errln("FAIL: Start year broken");
197
198 failure(status, "TestRuleAPI");
199 delete gc;
200 delete zone;
201 }
202
203 void
204 TimeZoneTest::findTransition(const TimeZone& tz,
205 UDate min, UDate max) {
206 UErrorCode ec = U_ZERO_ERROR;
207 UnicodeString id,s;
208 UBool startsInDST = tz.inDaylightTime(min, ec);
209 if (failure(ec, "TimeZone::inDaylightTime")) return;
210 if (tz.inDaylightTime(max, ec) == startsInDST) {
211 logln("Error: " + tz.getID(id) + ".inDaylightTime(" + dateToString(min) + ") = " + (startsInDST?"TRUE":"FALSE") +
212 ", inDaylightTime(" + dateToString(max) + ") = " + (startsInDST?"TRUE":"FALSE"));
213 return;
214 }
215 if (failure(ec, "TimeZone::inDaylightTime")) return;
216 while ((max - min) > INTERVAL) {
217 UDate mid = (min + max) / 2;
218 if (tz.inDaylightTime(mid, ec) == startsInDST) {
219 min = mid;
220 } else {
221 max = mid;
222 }
223 if (failure(ec, "TimeZone::inDaylightTime")) return;
224 }
225 min = 1000.0 * uprv_floor(min/1000.0);
226 max = 1000.0 * uprv_floor(max/1000.0);
227 logln(tz.getID(id) + " Before: " + min/1000 + " = " +
228 dateToString(min,s,tz));
229 logln(tz.getID(id) + " After: " + max/1000 + " = " +
230 dateToString(max,s,tz));
231 }
232
233 void
234 TimeZoneTest::testUsingBinarySearch(const TimeZone& tz,
235 UDate min, UDate max,
236 UDate expectedBoundary)
237 {
238 UErrorCode status = U_ZERO_ERROR;
239 UBool startsInDST = tz.inDaylightTime(min, status);
240 if (failure(status, "TimeZone::inDaylightTime")) return;
241 if (tz.inDaylightTime(max, status) == startsInDST) {
242 logln("Error: inDaylightTime(" + dateToString(max) + ") != " + ((!startsInDST)?"TRUE":"FALSE"));
243 return;
244 }
245 if (failure(status, "TimeZone::inDaylightTime")) return;
246 while ((max - min) > INTERVAL) {
247 UDate mid = (min + max) / 2;
248 if (tz.inDaylightTime(mid, status) == startsInDST) {
249 min = mid;
250 } else {
251 max = mid;
252 }
253 if (failure(status, "TimeZone::inDaylightTime")) return;
254 }
255 logln(UnicodeString("Binary Search Before: ") + uprv_floor(0.5 + min) + " = " + dateToString(min));
256 logln(UnicodeString("Binary Search After: ") + uprv_floor(0.5 + max) + " = " + dateToString(max));
257 UDate mindelta = expectedBoundary - min;
258 UDate maxdelta = max - expectedBoundary;
259 if (mindelta >= 0 &&
260 mindelta <= INTERVAL &&
261 maxdelta >= 0 &&
262 maxdelta <= INTERVAL)
263 logln(UnicodeString("PASS: Expected bdry: ") + expectedBoundary + " = " + dateToString(expectedBoundary));
264 else
265 errln(UnicodeString("FAIL: Expected bdry: ") + expectedBoundary + " = " + dateToString(expectedBoundary));
266 }
267
268 const UDate TimeZoneTest::INTERVAL = 100;
269
270 // ---------------------------------------------------------------------------------
271
272 // -------------------------------------
273
274 /**
275 * Test the offset of the PRT timezone.
276 */
277 void
278 TimeZoneTest::TestPRTOffset()
279 {
280 TimeZone* tz = TimeZone::createTimeZone("PRT");
281 if (tz == 0) {
282 errln("FAIL: TimeZone(PRT) is null");
283 }
284 else {
285 int32_t expectedHour = -4;
286 double expectedOffset = (((double)expectedHour) * millisPerHour);
287 double foundOffset = tz->getRawOffset();
288 int32_t foundHour = (int32_t)foundOffset / millisPerHour;
289 if (expectedOffset != foundOffset) {
290 errln("FAIL: Offset for PRT should be %d, found %d", expectedHour, foundHour);
291 } else {
292 logln("PASS: Offset for PRT should be %d, found %d", expectedHour, foundHour);
293 }
294 }
295 delete tz;
296 }
297
298 // -------------------------------------
299
300 /**
301 * Regress a specific bug with a sequence of API calls.
302 */
303 void
304 TimeZoneTest::TestVariousAPI518()
305 {
306 UErrorCode status = U_ZERO_ERROR;
307 TimeZone* time_zone = TimeZone::createTimeZone("PST");
308 UDate d = date(97, UCAL_APRIL, 30);
309 UnicodeString str;
310 logln("The timezone is " + time_zone->getID(str));
311 if (!time_zone->inDaylightTime(d, status)) errln("FAIL: inDaylightTime returned FALSE");
312 if (U_FAILURE(status)) { errln("FAIL: TimeZone::inDaylightTime failed"); return; }
313 if (!time_zone->useDaylightTime()) errln("FAIL: useDaylightTime returned FALSE");
314 if (time_zone->getRawOffset() != - 8 * millisPerHour) errln("FAIL: getRawOffset returned wrong value");
315 GregorianCalendar *gc = new GregorianCalendar(status);
316 if (U_FAILURE(status)) { errln("FAIL: Couldn't create GregorianCalendar"); return; }
317 gc->setTime(d, status);
318 if (U_FAILURE(status)) { errln("FAIL: GregorianCalendar::setTime failed"); return; }
319 if (time_zone->getOffset(gc->AD, gc->get(UCAL_YEAR, status), gc->get(UCAL_MONTH, status),
320 gc->get(UCAL_DATE, status), (uint8_t)gc->get(UCAL_DAY_OF_WEEK, status), 0, status) != - 7 * millisPerHour)
321 errln("FAIL: getOffset returned wrong value");
322 if (U_FAILURE(status)) { errln("FAIL: GregorianCalendar::set failed"); return; }
323 delete gc;
324 delete time_zone;
325 }
326
327 // -------------------------------------
328
329 /**
330 * Test the call which retrieves the available IDs.
331 */
332 void
333 TimeZoneTest::TestGetAvailableIDs913()
334 {
335 UErrorCode ec = U_ZERO_ERROR;
336 int32_t i;
337
338 #ifdef U_USE_TIMEZONE_OBSOLETE_2_8
339 // Test legacy API -- remove these tests when the corresponding API goes away (duh)
340 int32_t numIDs = -1;
341 const UnicodeString** ids = TimeZone::createAvailableIDs(numIDs);
342 if (ids == 0 || numIDs < 1) {
343 errln("FAIL: createAvailableIDs()");
344 } else {
345 UnicodeString buf("TimeZone::createAvailableIDs() = { ");
346 for(i=0; i<numIDs; ++i) {
347 if (i) buf.append(", ");
348 buf.append(*ids[i]);
349 }
350 buf.append(" } ");
351 logln(buf + numIDs);
352 // we own the array; the caller owns the contained strings (yuck)
353 uprv_free(ids);
354 }
355
356 numIDs = -1;
357 ids = TimeZone::createAvailableIDs(-8*U_MILLIS_PER_HOUR, numIDs);
358 if (ids == 0 || numIDs < 1) {
359 errln("FAIL: createAvailableIDs(-8:00)");
360 } else {
361 UnicodeString buf("TimeZone::createAvailableIDs(-8:00) = { ");
362 for(i=0; i<numIDs; ++i) {
363 if (i) buf.append(", ");
364 buf.append(*ids[i]);
365 }
366 buf.append(" } ");
367 logln(buf + numIDs);
368 // we own the array; the caller owns the contained strings (yuck)
369 uprv_free(ids);
370 }
371 numIDs = -1;
372 ids = TimeZone::createAvailableIDs("US", numIDs);
373 if (ids == 0 || numIDs < 1) {
374 errln("FAIL: createAvailableIDs(US) ids=%d, numIDs=%d", ids, numIDs);
375 } else {
376 UnicodeString buf("TimeZone::createAvailableIDs(US) = { ");
377 for(i=0; i<numIDs; ++i) {
378 if (i) buf.append(", ");
379 buf.append(*ids[i]);
380 }
381 buf.append(" } ");
382 logln(buf + numIDs);
383 // we own the array; the caller owns the contained strings (yuck)
384 uprv_free(ids);
385 }
386 #endif
387
388 UnicodeString str;
389 UnicodeString *buf = new UnicodeString("TimeZone::createEnumeration() = { ");
390 int32_t s_length;
391 StringEnumeration* s = TimeZone::createEnumeration();
392 s_length = s->count(ec);
393 for (i = 0; i < s_length;++i) {
394 if (i > 0) *buf += ", ";
395 if ((i & 1) == 0) {
396 *buf += *s->snext(ec);
397 } else {
398 *buf += UnicodeString(s->next(NULL, ec), "");
399 }
400
401 if((i % 5) == 4) {
402 // replace s with a clone of itself
403 StringEnumeration *s2 = s->clone();
404 if(s2 == NULL || s_length != s2->count(ec)) {
405 errln("TimezoneEnumeration.clone() failed");
406 } else {
407 delete s;
408 s = s2;
409 }
410 }
411 }
412 *buf += " };";
413 logln(*buf);
414
415 /* Confirm that the following zones can be retrieved: The first
416 * zone, the last zone, and one in-between. This tests the binary
417 * search through the system zone data.
418 */
419 s->reset(ec);
420 int32_t middle = s_length/2;
421 for (i=0; i<s_length; ++i) {
422 const UnicodeString* id = s->snext(ec);
423 if (i==0 || i==middle || i==(s_length-1)) {
424 TimeZone *z = TimeZone::createTimeZone(*id);
425 if (z == 0) {
426 errln(UnicodeString("FAIL: createTimeZone(") +
427 *id + ") -> 0");
428 } else if (z->getID(str) != *id) {
429 errln(UnicodeString("FAIL: createTimeZone(") +
430 *id + ") -> zone " + str);
431 } else {
432 logln(UnicodeString("OK: createTimeZone(") +
433 *id + ") succeeded");
434 }
435 delete z;
436 }
437 }
438 delete s;
439
440 buf->truncate(0);
441 *buf += "TimeZone::createEnumeration(GMT+01:00) = { ";
442
443 s = TimeZone::createEnumeration(1 * U_MILLIS_PER_HOUR);
444 s_length = s->count(ec);
445 for (i = 0; i < s_length;++i) {
446 if (i > 0) *buf += ", ";
447 *buf += *s->snext(ec);
448 }
449 delete s;
450 *buf += " };";
451 logln(*buf);
452
453
454 buf->truncate(0);
455 *buf += "TimeZone::createEnumeration(US) = { ";
456
457 s = TimeZone::createEnumeration("US");
458 s_length = s->count(ec);
459 for (i = 0; i < s_length;++i) {
460 if (i > 0) *buf += ", ";
461 *buf += *s->snext(ec);
462 }
463 *buf += " };";
464 logln(*buf);
465
466 TimeZone *tz = TimeZone::createTimeZone("PST");
467 if (tz != 0) logln("getTimeZone(PST) = " + tz->getID(str));
468 else errln("FAIL: getTimeZone(PST) = null");
469 delete tz;
470 tz = TimeZone::createTimeZone("America/Los_Angeles");
471 if (tz != 0) logln("getTimeZone(America/Los_Angeles) = " + tz->getID(str));
472 else errln("FAIL: getTimeZone(PST) = null");
473 delete tz;
474
475 // @bug 4096694
476 tz = TimeZone::createTimeZone("NON_EXISTENT");
477 UnicodeString temp;
478 if (tz == 0)
479 errln("FAIL: getTimeZone(NON_EXISTENT) = null");
480 else if (tz->getID(temp) != "GMT")
481 errln("FAIL: getTimeZone(NON_EXISTENT) = " + temp);
482 delete tz;
483
484 delete buf;
485 delete s;
486 }
487
488
489 /**
490 * NOTE: As of ICU 2.8, this test confirms that the "tz.alias"
491 * file, used to build ICU alias zones, is working. It also
492 * looks at some genuine Olson compatibility IDs. [aliu]
493 *
494 * This test is problematic. It should really just confirm that
495 * the list of compatibility zone IDs exist and are somewhat
496 * meaningful (that is, they aren't all aliases of GMT). It goes a
497 * bit further -- it hard-codes expectations about zone behavior,
498 * when in fact zones are redefined quite frequently. ICU's build
499 * process means that it is easy to update ICU to contain the
500 * latest Olson zone data, but if a zone tested here changes, then
501 * this test will fail. I have updated the test for 1999j data,
502 * but further updates will probably be required. Note that some
503 * of the concerts listed below no longer apply -- in particular,
504 * we do NOT overwrite real UNIX zones with 3-letter IDs. There
505 * are two points of overlap as of 1999j: MET and EET. These are
506 * both real UNIX zones, so we just use the official
507 * definition. This test has been updated to reflect this.
508 * 12/3/99 aliu
509 *
510 * Added tests for additional zones and aliases from the icuzones file.
511 * Markus Scherer 2006-nov-06
512 *
513 * [srl - from java - 7/5/1998]
514 * @bug 4130885
515 * Certain short zone IDs, used since 1.1.x, are incorrect.
516 *
517 * The worst of these is:
518 *
519 * "CAT" (Central African Time) should be GMT+2:00, but instead returns a
520 * zone at GMT-1:00. The zone at GMT-1:00 should be called EGT, CVT, EGST,
521 * or AZOST, depending on which zone is meant, but in no case is it CAT.
522 *
523 * Other wrong zone IDs:
524 *
525 * ECT (European Central Time) GMT+1:00: ECT is Ecuador Time,
526 * GMT-5:00. European Central time is abbreviated CEST.
527 *
528 * SST (Solomon Island Time) GMT+11:00. SST is actually Samoa Standard Time,
529 * GMT-11:00. Solomon Island time is SBT.
530 *
531 * NST (New Zealand Time) GMT+12:00. NST is the abbreviation for
532 * Newfoundland Standard Time, GMT-3:30. New Zealanders use NZST.
533 *
534 * AST (Alaska Standard Time) GMT-9:00. [This has already been noted in
535 * another bug.] It should be "AKST". AST is Atlantic Standard Time,
536 * GMT-4:00.
537 *
538 * PNT (Phoenix Time) GMT-7:00. PNT usually means Pitcairn Time,
539 * GMT-8:30. There is no standard abbreviation for Phoenix time, as distinct
540 * from MST with daylight savings.
541 *
542 * In addition to these problems, a number of zones are FAKE. That is, they
543 * don't match what people use in the real world.
544 *
545 * FAKE zones:
546 *
547 * EET (should be EEST)
548 * ART (should be EEST)
549 * MET (should be IRST)
550 * NET (should be AMST)
551 * PLT (should be PKT)
552 * BST (should be BDT)
553 * VST (should be ICT)
554 * CTT (should be CST) +
555 * ACT (should be CST) +
556 * AET (should be EST) +
557 * MIT (should be WST) +
558 * IET (should be EST) +
559 * PRT (should be AST) +
560 * CNT (should be NST)
561 * AGT (should be ARST)
562 * BET (should be EST) +
563 *
564 * + A zone with the correct name already exists and means something
565 * else. E.g., EST usually indicates the US Eastern zone, so it cannot be
566 * used for Brazil (BET).
567 */
568 void TimeZoneTest::TestShortZoneIDs()
569 {
570 int32_t i;
571 // Create a small struct to hold the array
572 struct
573 {
574 const char *id;
575 int32_t offset;
576 UBool daylight;
577 }
578 kReferenceList [] =
579 {
580 {"MIT", -660, FALSE},
581 {"HST", -600, FALSE},
582 {"AST", -540, TRUE},
583 {"PST", -480, TRUE},
584 {"PNT", -420, FALSE},
585 {"MST", -420, FALSE}, // updated Aug 2003 aliu
586 {"CST", -360, TRUE},
587 {"IET", -300, TRUE}, // updated Jan 2006 srl
588 {"EST", -300, FALSE}, // updated Aug 2003 aliu
589 {"PRT", -240, FALSE},
590 {"CNT", -210, TRUE},
591 {"AGT", -180, TRUE}, // updated by tzdata2007k
592 {"BET", -180, TRUE},
593 // "CAT", -60, FALSE, // Wrong:
594 // As of bug 4130885, fix CAT (Central Africa)
595 {"CAT", 120, FALSE}, // Africa/Harare
596 {"GMT", 0, FALSE},
597 {"UTC", 0, FALSE}, // ** srl: seems broken in C++
598 {"ECT", 60, TRUE},
599 {"ART", 120, TRUE},
600 {"EET", 120, TRUE},
601 {"EAT", 180, FALSE},
602 {"MET", 60, TRUE}, // updated 12/3/99 aliu
603 {"NET", 240, TRUE}, // updated 12/3/99 aliu
604 {"PLT", 300, TRUE}, // updated by 2008c
605 {"IST", 330, FALSE},
606 {"BST", 360, FALSE},
607 {"VST", 420, FALSE},
608 {"CTT", 480, FALSE}, // updated Aug 2003 aliu
609 {"JST", 540, FALSE},
610 {"ACT", 570, FALSE}, // updated Aug 2003 aliu
611 {"AET", 600, TRUE},
612 {"SST", 660, FALSE},
613 // "NST", 720, FALSE,
614 // As of bug 4130885, fix NST (New Zealand)
615 {"NST", 720, TRUE}, // Pacific/Auckland
616 {"",0,FALSE}
617 };
618
619
620 for(i=0;kReferenceList[i].id[0];i++) {
621 UnicodeString itsID(kReferenceList[i].id);
622 UBool ok = TRUE;
623 // Check existence.
624 TimeZone *tz = TimeZone::createTimeZone(itsID);
625 if (!tz) {
626 errln("FAIL: Time Zone " + itsID + " does not exist!");
627 continue;
628 }
629
630 // Check daylight usage.
631 UBool usesDaylight = tz->useDaylightTime();
632 if (usesDaylight != kReferenceList[i].daylight) {
633 errln("FAIL: Time Zone " + itsID + " use daylight is " +
634 (usesDaylight?"TRUE":"FALSE") +
635 " but it should be " +
636 ((kReferenceList[i].daylight)?"TRUE":"FALSE"));
637 ok = FALSE;
638 }
639
640 // Check offset
641 int32_t offsetInMinutes = tz->getRawOffset()/60000;
642 if (offsetInMinutes != kReferenceList[i].offset) {
643 errln("FAIL: Time Zone " + itsID + " raw offset is " +
644 offsetInMinutes +
645 " but it should be " + kReferenceList[i].offset);
646 ok = FALSE;
647 }
648
649 if (ok) {
650 logln("OK: " + itsID +
651 " useDaylightTime() & getRawOffset() as expected");
652 }
653 delete tz;
654 }
655
656
657 // OK now test compat
658 logln("Testing for compatibility zones");
659
660 const char* compatibilityMap[] = {
661 // This list is copied from tz.alias. If tz.alias
662 // changes, this list must be updated. Current as of Mar 2007
663 "ACT", "Australia/Darwin",
664 "AET", "Australia/Sydney",
665 "AGT", "America/Buenos_Aires",
666 "ART", "Africa/Cairo",
667 "AST", "America/Anchorage",
668 "BET", "America/Sao_Paulo",
669 "BST", "Asia/Dhaka", // # spelling changed in 2000h; was Asia/Dacca
670 "CAT", "Africa/Harare",
671 "CNT", "America/St_Johns",
672 "CST", "America/Chicago",
673 "CTT", "Asia/Shanghai",
674 "EAT", "Africa/Addis_Ababa",
675 "ECT", "Europe/Paris",
676 // EET Europe/Istanbul # EET is a standard UNIX zone
677 // "EST", "America/New_York", # Defined as -05:00
678 // "HST", "Pacific/Honolulu", # Defined as -10:00
679 "IET", "America/Indianapolis",
680 "IST", "Asia/Calcutta",
681 "JST", "Asia/Tokyo",
682 // MET Asia/Tehran # MET is a standard UNIX zone
683 "MIT", "Pacific/Apia",
684 // "MST", "America/Denver", # Defined as -07:00
685 "NET", "Asia/Yerevan",
686 "NST", "Pacific/Auckland",
687 "PLT", "Asia/Karachi",
688 "PNT", "America/Phoenix",
689 "PRT", "America/Puerto_Rico",
690 "PST", "America/Los_Angeles",
691 "SST", "Pacific/Guadalcanal",
692 "UTC", "Etc/GMT",
693 "VST", "Asia/Saigon",
694 "","",""
695 };
696
697 for (i=0;*compatibilityMap[i];i+=2) {
698 UnicodeString itsID;
699
700 const char *zone1 = compatibilityMap[i];
701 const char *zone2 = compatibilityMap[i+1];
702
703 TimeZone *tz1 = TimeZone::createTimeZone(zone1);
704 TimeZone *tz2 = TimeZone::createTimeZone(zone2);
705
706 if (!tz1) {
707 errln(UnicodeString("FAIL: Could not find short ID zone ") + zone1);
708 }
709 if (!tz2) {
710 errln(UnicodeString("FAIL: Could not find long ID zone ") + zone2);
711 }
712
713 if (tz1 && tz2) {
714 // make NAME same so comparison will only look at the rest
715 tz2->setID(tz1->getID(itsID));
716
717 if (*tz1 != *tz2) {
718 errln("FAIL: " + UnicodeString(zone1) +
719 " != " + UnicodeString(zone2));
720 } else {
721 logln("OK: " + UnicodeString(zone1) +
722 " == " + UnicodeString(zone2));
723 }
724 }
725
726 delete tz1;
727 delete tz2;
728 }
729 }
730
731 /**
732 * Utility function for TestCustomParse
733 */
734 UnicodeString& TimeZoneTest::formatMinutes(int32_t min, UnicodeString& rv)
735 {
736 rv.remove();
737
738 char sign = '+';
739 if (min < 0) { sign = '-'; min = -min; }
740 int h = min/60;
741 min = min%60;
742
743 rv += UChar(sign);
744 if(h > 10)
745 rv += UChar(0x0030 + (h/10));
746 rv += UChar(0x0030 + (h%10));
747
748 rv += ":";
749
750 if(min > 10)
751 rv += UChar(0x0030 + (min/10));
752 else
753 rv += "0";
754
755 rv += UChar(0x0030 + (min%10));
756
757 return rv;
758 }
759
760
761 /**
762 * As part of the VM fix (see CCC approved RFE 4028006, bug
763 * 4044013), TimeZone.getTimeZone() has been modified to recognize
764 * generic IDs of the form GMT[+-]hh:mm, GMT[+-]hhmm, and
765 * GMT[+-]hh. Test this behavior here.
766 *
767 * @bug 4044013
768 */
769 void TimeZoneTest::TestCustomParse()
770 {
771 int32_t i;
772 const int32_t kUnparseable = 604800; // the number of seconds in a week. More than any offset should be.
773 const UnicodeString kExpectedCustomID = "Custom";
774
775 struct
776 {
777 const char *customId;
778 int32_t expectedOffset;
779 }
780 kData[] =
781 {
782 // ID Expected offset in minutes
783 //{"GMT", kUnparseable}, //Isn't custom. Can't test it here. [returns normal GMT]
784 {"GMT-YOUR.AD.HERE", kUnparseable},
785 // {"GMT0", kUnparseable}, // ICU 2.8: An Olson zone ID
786 // {"GMT+0", (0)}, // ICU 2.8: An Olson zone ID
787 {"GMT+1", (60)},
788 {"GMT-0030", (-30)},
789 {"GMT+15:99", (15*60+99)},
790 {"GMT+", kUnparseable},
791 {"GMT-", kUnparseable},
792 {"GMT+0:", kUnparseable},
793 {"GMT-:", kUnparseable},
794 {"GMT-YOUR.AD.HERE", kUnparseable},
795 {"GMT+0010", (10)}, // Interpret this as 00:10
796 {"GMT-10", (-10*60)},
797 {"GMT+30", (30)},
798 {"GMT-3:30", (-(3*60+30))},
799 {"GMT-230", (-(2*60+30))},
800 {0, 0}
801 };
802
803 for (i=0; kData[i].customId != 0; i++)
804 {
805 UnicodeString id(kData[i].customId);
806 int32_t exp = kData[i].expectedOffset;
807 /*
808 { // for no data test Jitterbug 4354
809 UErrorCode success = U_ZERO_ERROR;
810 NumberFormat* numberFormat = NumberFormat::createInstance(success);
811 if (U_FAILURE(success)) {
812 dataerrln(" NumberFormat::createInstance() error");
813 return;
814 }
815 delete numberFormat;
816 }
817 */
818
819 TimeZone *zone = TimeZone::createTimeZone(id);
820 UnicodeString itsID, temp;
821
822 logln();
823 logln("testing # " + formatMinutes(i, temp) + id);
824
825 /*
826 if(zone == NULL)
827 {
828 errln("FAIL: Could not createTimeZone(" + id + "). Returned NULL.");
829 continue;
830 }
831 */
832
833
834 if (! zone->getID(itsID).compare("GMT"))
835 //if(zone == NULL)
836 {
837 logln(id + " -> generic GMT");
838 // When TimeZone.getTimeZone() can't parse the id, it
839 // returns GMT -- a dubious practice, but required for
840 // backward compatibility.
841 if (exp != kUnparseable) {
842 errln("FAIL: Expected offset of " + formatMinutes(exp,temp) +
843 " for " + id + ", got parse failure");
844 }
845 }
846 else
847 {
848 zone->getID(itsID);
849 int32_t ioffset = zone->getRawOffset()/60000;
850 UnicodeString offset;
851 formatMinutes(ioffset, offset);
852 logln(id + " -> " + itsID + " GMT" + offset);
853 if (exp == kUnparseable)
854 {
855 errln("FAIL: Expected parse failure for " + id +
856 ", got offset of " + offset +
857 ", id " + itsID);
858 }
859 else if (ioffset != exp ||
860 (itsID.compare(kExpectedCustomID) != 0))
861 {
862 errln("Expected offset of " + formatMinutes(exp,temp) +
863 ", id Custom, for " + id +
864 ", got offset of " + offset +
865 ", id " + itsID);
866 }
867 }
868 delete zone;
869 }
870 }
871
872 static const UVersionInfo ICU_37 = {3,7,0,0};
873
874 void
875 TimeZoneTest::TestAliasedNames()
876 {
877 struct {
878 const char *from;
879 const char *to;
880 } kData[] = {
881 /* Generated by org.unicode.cldr.tool.CountItems */
882
883 /* zoneID, canonical zoneID */
884 {"Africa/Timbuktu", "Africa/Bamako"},
885 {"America/Argentina/Buenos_Aires", "America/Buenos_Aires"},
886 {"America/Argentina/Catamarca", "America/Catamarca"},
887 {"America/Argentina/ComodRivadavia", "America/Catamarca"},
888 {"America/Argentina/Cordoba", "America/Cordoba"},
889 {"America/Argentina/Jujuy", "America/Jujuy"},
890 {"America/Argentina/Mendoza", "America/Mendoza"},
891 {"America/Atka", "America/Adak"},
892 {"America/Ensenada", "America/Tijuana"},
893 {"America/Fort_Wayne", "America/Indiana/Indianapolis"},
894 {"America/Indianapolis", "America/Indiana/Indianapolis"},
895 {"America/Knox_IN", "America/Indiana/Knox"},
896 {"America/Louisville", "America/Kentucky/Louisville"},
897 {"America/Porto_Acre", "America/Rio_Branco"},
898 {"America/Rosario", "America/Cordoba"},
899 {"America/Virgin", "America/St_Thomas"},
900 {"Asia/Ashkhabad", "Asia/Ashgabat"},
901 {"Asia/Chungking", "Asia/Chongqing"},
902 {"Asia/Dacca", "Asia/Dhaka"},
903 {"Asia/Istanbul", "Europe/Istanbul"},
904 {"Asia/Macao", "Asia/Macau"},
905 {"Asia/Tel_Aviv", "Asia/Jerusalem"},
906 {"Asia/Thimbu", "Asia/Thimphu"},
907 {"Asia/Ujung_Pandang", "Asia/Makassar"},
908 {"Asia/Ulan_Bator", "Asia/Ulaanbaatar"},
909 {"Australia/ACT", "Australia/Sydney"},
910 {"Australia/Canberra", "Australia/Sydney"},
911 {"Australia/LHI", "Australia/Lord_Howe"},
912 {"Australia/NSW", "Australia/Sydney"},
913 {"Australia/North", "Australia/Darwin"},
914 {"Australia/Queensland", "Australia/Brisbane"},
915 {"Australia/South", "Australia/Adelaide"},
916 {"Australia/Tasmania", "Australia/Hobart"},
917 {"Australia/Victoria", "Australia/Melbourne"},
918 {"Australia/West", "Australia/Perth"},
919 {"Australia/Yancowinna", "Australia/Broken_Hill"},
920 {"Brazil/Acre", "America/Rio_Branco"},
921 {"Brazil/DeNoronha", "America/Noronha"},
922 {"Brazil/East", "America/Sao_Paulo"},
923 {"Brazil/West", "America/Manaus"},
924 {"Canada/Atlantic", "America/Halifax"},
925 {"Canada/Central", "America/Winnipeg"},
926 {"Canada/East-Saskatchewan", "America/Regina"},
927 {"Canada/Eastern", "America/Toronto"},
928 {"Canada/Mountain", "America/Edmonton"},
929 {"Canada/Newfoundland", "America/St_Johns"},
930 {"Canada/Pacific", "America/Vancouver"},
931 {"Canada/Saskatchewan", "America/Regina"},
932 {"Canada/Yukon", "America/Whitehorse"},
933 {"Chile/Continental", "America/Santiago"},
934 {"Chile/EasterIsland", "Pacific/Easter"},
935 {"Cuba", "America/Havana"},
936 {"Egypt", "Africa/Cairo"},
937 {"Eire", "Europe/Dublin"},
938 {"Etc/GMT+0", "Etc/GMT"},
939 {"Etc/GMT-0", "Etc/GMT"},
940 {"Etc/GMT0", "Etc/GMT"},
941 {"Etc/Greenwich", "Etc/GMT"},
942 {"Etc/UCT", "Etc/GMT"},
943 {"Etc/UTC", "Etc/GMT"},
944 {"Etc/Universal", "Etc/GMT"},
945 {"Etc/Zulu", "Etc/GMT"},
946 {"Europe/Belfast", "Europe/London"},
947 {"Europe/Nicosia", "Asia/Nicosia"},
948 {"Europe/Tiraspol", "Europe/Chisinau"},
949 {"GB", "Europe/London"},
950 {"GB-Eire", "Europe/London"},
951 {"GMT", "Etc/GMT"},
952 {"GMT+0", "Etc/GMT"},
953 {"GMT-0", "Etc/GMT"},
954 {"GMT0", "Etc/GMT"},
955 {"Greenwich", "Etc/GMT"},
956 {"Hongkong", "Asia/Hong_Kong"},
957 {"Iceland", "Atlantic/Reykjavik"},
958 {"Iran", "Asia/Tehran"},
959 {"Israel", "Asia/Jerusalem"},
960 {"Jamaica", "America/Jamaica"},
961 {"Japan", "Asia/Tokyo"},
962 {"Kwajalein", "Pacific/Kwajalein"},
963 {"Libya", "Africa/Tripoli"},
964 {"Mexico/BajaNorte", "America/Tijuana"},
965 {"Mexico/BajaSur", "America/Mazatlan"},
966 {"Mexico/General", "America/Mexico_City"},
967 {"NZ", "Pacific/Auckland"},
968 {"NZ-CHAT", "Pacific/Chatham"},
969 {"Navajo", "America/Shiprock"},
970 {"PRC", "Asia/Shanghai"},
971 {"Pacific/Samoa", "Pacific/Pago_Pago"},
972 {"Pacific/Yap", "Pacific/Truk"},
973 {"Poland", "Europe/Warsaw"},
974 {"Portugal", "Europe/Lisbon"},
975 {"ROC", "Asia/Taipei"},
976 {"ROK", "Asia/Seoul"},
977 {"Singapore", "Asia/Singapore"},
978 {"Turkey", "Europe/Istanbul"},
979 {"UCT", "Etc/GMT"},
980 {"US/Alaska", "America/Anchorage"},
981 {"US/Aleutian", "America/Adak"},
982 {"US/Arizona", "America/Phoenix"},
983 {"US/Central", "America/Chicago"},
984 {"US/East-Indiana", "America/Indiana/Indianapolis"},
985 {"US/Eastern", "America/New_York"},
986 {"US/Hawaii", "Pacific/Honolulu"},
987 {"US/Indiana-Starke", "America/Indiana/Knox"},
988 {"US/Michigan", "America/Detroit"},
989 {"US/Mountain", "America/Denver"},
990 {"US/Pacific", "America/Los_Angeles"},
991 {"US/Pacific-New", "America/Los_Angeles"},
992 {"US/Samoa", "Pacific/Pago_Pago"},
993 {"UTC", "Etc/GMT"},
994 {"Universal", "Etc/GMT"},
995 {"W-SU", "Europe/Moscow"},
996 {"Zulu", "Etc/GMT"},
997 /* Total: 113 */
998
999 };
1000
1001 TimeZone::EDisplayType styles[] = { TimeZone::SHORT, TimeZone::LONG };
1002 UBool useDst[] = { FALSE, TRUE };
1003 int32_t noLoc = uloc_countAvailable();
1004
1005 if(isICUVersionAtLeast(ICU_37)) {
1006 errln("This test needs to be fixed. This test fails in exhaustive mode because we need to implement generic timezones.\n");
1007 }
1008
1009 int32_t i, j, k, loc;
1010 UnicodeString fromName, toName;
1011 TimeZone *from = NULL, *to = NULL;
1012 for(i = 0; i < (int32_t)(sizeof(kData)/sizeof(kData[0])); i++) {
1013 from = TimeZone::createTimeZone(kData[i].from);
1014 to = TimeZone::createTimeZone(kData[i].to);
1015 if(!from->hasSameRules(*to)) {
1016 errln("different at %i\n", i);
1017 }
1018 if(!quick && isICUVersionAtLeast(ICU_37)) {
1019 errln("This test needs to be fixed. This test fails in exhaustive mode because we need to implement generic timezones.\n");
1020 for(loc = 0; loc < noLoc; loc++) {
1021 const char* locale = uloc_getAvailable(loc);
1022 for(j = 0; j < (int32_t)(sizeof(styles)/sizeof(styles[0])); j++) {
1023 for(k = 0; k < (int32_t)(sizeof(useDst)/sizeof(useDst[0])); k++) {
1024 fromName.remove();
1025 toName.remove();
1026 from->getDisplayName(useDst[k], styles[j],locale, fromName);
1027 to->getDisplayName(useDst[k], styles[j], locale, toName);
1028 if(fromName.compare(toName) != 0) {
1029 errln("Fail: Expected "+toName+" but got " + prettify(fromName)
1030 + " for locale: " + locale + " index: "+ loc
1031 + " to id "+ kData[i].to
1032 + " from id " + kData[i].from);
1033 }
1034 }
1035 }
1036 }
1037 } else {
1038 fromName.remove();
1039 toName.remove();
1040 from->getDisplayName(fromName);
1041 to->getDisplayName(toName);
1042 if(fromName.compare(toName) != 0) {
1043 errln("Fail: Expected "+toName+" but got " + fromName);
1044 }
1045 }
1046 delete from;
1047 delete to;
1048 }
1049 }
1050
1051 /**
1052 * Test the basic functionality of the getDisplayName() API.
1053 *
1054 * @bug 4112869
1055 * @bug 4028006
1056 *
1057 * See also API change request A41.
1058 *
1059 * 4/21/98 - make smarter, so the test works if the ext resources
1060 * are present or not.
1061 */
1062 void
1063 TimeZoneTest::TestDisplayName()
1064 {
1065 UErrorCode status = U_ZERO_ERROR;
1066 int32_t i;
1067 TimeZone *zone = TimeZone::createTimeZone("PST");
1068 UnicodeString name;
1069 zone->getDisplayName(Locale::getEnglish(), name);
1070 logln("PST->" + name);
1071 if (name.compare("Pacific Standard Time") != 0)
1072 errln("Fail: Expected \"Pacific Standard Time\" but got " + name);
1073
1074 //*****************************************************************
1075 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
1076 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
1077 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
1078 //*****************************************************************
1079 struct
1080 {
1081 UBool useDst;
1082 TimeZone::EDisplayType style;
1083 const char *expect;
1084 } kData[] = {
1085 {FALSE, TimeZone::SHORT, "PST"},
1086 {TRUE, TimeZone::SHORT, "PDT"},
1087 {FALSE, TimeZone::LONG, "Pacific Standard Time"},
1088 {TRUE, TimeZone::LONG, "Pacific Daylight Time"},
1089
1090 {FALSE, TimeZone::LONG, ""}
1091 };
1092
1093 for (i=0; kData[i].expect[0] != '\0'; i++)
1094 {
1095 name.remove();
1096 name = zone->getDisplayName(kData[i].useDst,
1097 kData[i].style,
1098 Locale::getEnglish(), name);
1099 if (name.compare(kData[i].expect) != 0)
1100 errln("Fail: Expected " + UnicodeString(kData[i].expect) + "; got " + name);
1101 logln("PST [with options]->" + name);
1102 }
1103 for (i=0; kData[i].expect[0] != '\0'; i++)
1104 {
1105 name.remove();
1106 name = zone->getDisplayName(kData[i].useDst,
1107 kData[i].style, name);
1108 if (name.compare(kData[i].expect) != 0)
1109 errln("Fail: Expected " + UnicodeString(kData[i].expect) + "; got " + name);
1110 logln("PST [with options]->" + name);
1111 }
1112
1113
1114 // Make sure that we don't display the DST name by constructing a fake
1115 // PST zone that has DST all year long.
1116 SimpleTimeZone *zone2 = new SimpleTimeZone(0, "PST");
1117
1118 zone2->setStartRule(UCAL_JANUARY, 1, 0, 0, status);
1119 zone2->setEndRule(UCAL_DECEMBER, 31, 0, 0, status);
1120
1121 UnicodeString inDaylight;
1122 if (zone2->inDaylightTime(UDate(0), status)) {
1123 inDaylight = UnicodeString("TRUE");
1124 } else {
1125 inDaylight = UnicodeString("FALSE");
1126 }
1127 logln(UnicodeString("Modified PST inDaylightTime->") + inDaylight );
1128 if(U_FAILURE(status))
1129 {
1130 errln("Some sort of error..." + UnicodeString(u_errorName(status))); // REVISIT
1131 }
1132 name.remove();
1133 name = zone2->getDisplayName(Locale::getEnglish(),name);
1134 logln("Modified PST->" + name);
1135 if (name.compare("Pacific Standard Time") != 0)
1136 errln("Fail: Expected \"Pacific Standard Time\"");
1137
1138 // Make sure we get the default display format for Locales
1139 // with no display name data.
1140 Locale mt_MT("mt_MT");
1141 name.remove();
1142 name = zone->getDisplayName(mt_MT,name);
1143 //*****************************************************************
1144 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
1145 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
1146 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
1147 //*****************************************************************
1148 logln("PST(mt_MT)->" + name);
1149
1150 // *** REVISIT SRL how in the world do I check this? looks java specific.
1151 // Now be smart -- check to see if zh resource is even present.
1152 // If not, we expect the en fallback behavior.
1153 ResourceBundle enRB(NULL,
1154 Locale::getEnglish(), status);
1155 if(U_FAILURE(status))
1156 errln("Couldn't get ResourceBundle for en");
1157
1158 ResourceBundle mtRB(NULL,
1159 mt_MT, status);
1160 //if(U_FAILURE(status))
1161 // errln("Couldn't get ResourceBundle for mt_MT");
1162
1163 UBool noZH = U_FAILURE(status);
1164
1165 if (noZH) {
1166 logln("Warning: Not testing the mt_MT behavior because resource is absent");
1167 if (name != "Pacific Standard Time")
1168 errln("Fail: Expected Pacific Standard Time");
1169 }
1170
1171
1172 if (name.compare("GMT-08:00") &&
1173 name.compare("GMT-8:00") &&
1174 name.compare("GMT-0800") &&
1175 name.compare("GMT-800")) {
1176 errln(UnicodeString("Fail: Expected GMT-08:00 or something similar for PST in mt_MT but got ") + name );
1177 errln("************************************************************");
1178 errln("THE ABOVE FAILURE MAY JUST MEAN THE LOCALE DATA HAS CHANGED");
1179 errln("************************************************************");
1180 }
1181
1182 // Now try a non-existent zone
1183 delete zone2;
1184 zone2 = new SimpleTimeZone(90*60*1000, "xyzzy");
1185 name.remove();
1186 name = zone2->getDisplayName(Locale::getEnglish(),name);
1187 logln("GMT+90min->" + name);
1188 if (name.compare("GMT+01:30") &&
1189 name.compare("GMT+1:30") &&
1190 name.compare("GMT+0130") &&
1191 name.compare("GMT+130"))
1192 errln("Fail: Expected GMT+01:30 or something similar");
1193 name.truncate(0);
1194 zone2->getDisplayName(name);
1195 logln("GMT+90min->" + name);
1196 if (name.compare("GMT+01:30") &&
1197 name.compare("GMT+1:30") &&
1198 name.compare("GMT+0130") &&
1199 name.compare("GMT+130"))
1200 errln("Fail: Expected GMT+01:30 or something similar");
1201 // clean up
1202 delete zone;
1203 delete zone2;
1204 }
1205
1206 /**
1207 * @bug 4107276
1208 */
1209 void
1210 TimeZoneTest::TestDSTSavings()
1211 {
1212 UErrorCode status = U_ZERO_ERROR;
1213 // It might be better to find a way to integrate this test into the main TimeZone
1214 // tests above, but I don't have time to figure out how to do this (or if it's
1215 // even really a good idea). Let's consider that a future. --rtg 1/27/98
1216 SimpleTimeZone *tz = new SimpleTimeZone(-5 * U_MILLIS_PER_HOUR, "dstSavingsTest",
1217 UCAL_MARCH, 1, 0, 0, UCAL_SEPTEMBER, 1, 0, 0,
1218 (int32_t)(0.5 * U_MILLIS_PER_HOUR), status);
1219 if(U_FAILURE(status))
1220 errln("couldn't create TimeZone");
1221
1222 if (tz->getRawOffset() != -5 * U_MILLIS_PER_HOUR)
1223 errln(UnicodeString("Got back a raw offset of ") + (tz->getRawOffset() / U_MILLIS_PER_HOUR) +
1224 " hours instead of -5 hours.");
1225 if (!tz->useDaylightTime())
1226 errln("Test time zone should use DST but claims it doesn't.");
1227 if (tz->getDSTSavings() != 0.5 * U_MILLIS_PER_HOUR)
1228 errln(UnicodeString("Set DST offset to 0.5 hour, but got back ") + (tz->getDSTSavings() /
1229 U_MILLIS_PER_HOUR) + " hours instead.");
1230
1231 int32_t offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JANUARY, 1,
1232 UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status);
1233 if (offset != -5 * U_MILLIS_PER_HOUR)
1234 errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ")
1235 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1236
1237 offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JUNE, 1, UCAL_MONDAY,
1238 10 * U_MILLIS_PER_HOUR,status);
1239 if (offset != -4.5 * U_MILLIS_PER_HOUR)
1240 errln(UnicodeString("The offset for 10 AM, 6/1/98 should have been -4.5 hours, but we got ")
1241 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1242
1243 tz->setDSTSavings(U_MILLIS_PER_HOUR, status);
1244 offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JANUARY, 1,
1245 UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status);
1246 if (offset != -5 * U_MILLIS_PER_HOUR)
1247 errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ")
1248 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1249
1250 offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JUNE, 1, UCAL_MONDAY,
1251 10 * U_MILLIS_PER_HOUR,status);
1252 if (offset != -4 * U_MILLIS_PER_HOUR)
1253 errln(UnicodeString("The offset for 10 AM, 6/1/98 (with a 1-hour DST offset) should have been -4 hours, but we got ")
1254 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1255
1256 delete tz;
1257 }
1258
1259 /**
1260 * @bug 4107570
1261 */
1262 void
1263 TimeZoneTest::TestAlternateRules()
1264 {
1265 // Like TestDSTSavings, this test should probably be integrated somehow with the main
1266 // test at the top of this class, but I didn't have time to figure out how to do that.
1267 // --rtg 1/28/98
1268
1269 SimpleTimeZone tz(-5 * U_MILLIS_PER_HOUR, "alternateRuleTest");
1270
1271 // test the day-of-month API
1272 UErrorCode status = U_ZERO_ERROR;
1273 tz.setStartRule(UCAL_MARCH, 10, 12 * U_MILLIS_PER_HOUR, status);
1274 if(U_FAILURE(status))
1275 errln("tz.setStartRule failed");
1276 tz.setEndRule(UCAL_OCTOBER, 20, 12 * U_MILLIS_PER_HOUR, status);
1277 if(U_FAILURE(status))
1278 errln("tz.setStartRule failed");
1279
1280 int32_t offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 5,
1281 UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status);
1282 if (offset != -5 * U_MILLIS_PER_HOUR)
1283 errln(UnicodeString("The offset for 10AM, 3/5/98 should have been -5 hours, but we got ")
1284 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1285
1286 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 15,
1287 UCAL_SUNDAY, 10 * millisPerHour,status);
1288 if (offset != -4 * U_MILLIS_PER_HOUR)
1289 errln(UnicodeString("The offset for 10AM, 3/15/98 should have been -4 hours, but we got ")
1290 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1291
1292 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 15,
1293 UCAL_THURSDAY, 10 * millisPerHour,status);
1294 if (offset != -4 * U_MILLIS_PER_HOUR)
1295 errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ") + (offset / U_MILLIS_PER_HOUR) + " hours.");
1296
1297 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 25,
1298 UCAL_SUNDAY, 10 * millisPerHour,status);
1299 if (offset != -5 * U_MILLIS_PER_HOUR)
1300 errln(UnicodeString("The offset for 10AM, 10/25/98 should have been -5 hours, but we got ")
1301 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1302
1303 // test the day-of-week-after-day-in-month API
1304 tz.setStartRule(UCAL_MARCH, 10, UCAL_FRIDAY, 12 * millisPerHour, TRUE, status);
1305 if(U_FAILURE(status))
1306 errln("tz.setStartRule failed");
1307 tz.setEndRule(UCAL_OCTOBER, 20, UCAL_FRIDAY, 12 * millisPerHour, FALSE, status);
1308 if(U_FAILURE(status))
1309 errln("tz.setStartRule failed");
1310
1311 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 11,
1312 UCAL_WEDNESDAY, 10 * millisPerHour,status);
1313 if (offset != -5 * U_MILLIS_PER_HOUR)
1314 errln(UnicodeString("The offset for 10AM, 3/11/98 should have been -5 hours, but we got ")
1315 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1316
1317 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 14,
1318 UCAL_SATURDAY, 10 * millisPerHour,status);
1319 if (offset != -4 * U_MILLIS_PER_HOUR)
1320 errln(UnicodeString("The offset for 10AM, 3/14/98 should have been -4 hours, but we got ")
1321 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1322
1323 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 15,
1324 UCAL_THURSDAY, 10 * millisPerHour,status);
1325 if (offset != -4 * U_MILLIS_PER_HOUR)
1326 errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ")
1327 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1328
1329 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 17,
1330 UCAL_SATURDAY, 10 * millisPerHour,status);
1331 if (offset != -5 * U_MILLIS_PER_HOUR)
1332 errln(UnicodeString("The offset for 10AM, 10/17/98 should have been -5 hours, but we got ")
1333 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1334 }
1335
1336 void TimeZoneTest::TestFractionalDST() {
1337 const char* tzName = "Australia/Lord_Howe"; // 30 min offset
1338 TimeZone* tz_icu = TimeZone::createTimeZone(tzName);
1339 int dst_icu = tz_icu->getDSTSavings();
1340 UnicodeString id;
1341 int32_t expected = 1800000;
1342 if (expected != dst_icu) {
1343 errln(UnicodeString("java reports dst savings of ") + expected +
1344 " but icu reports " + dst_icu +
1345 " for tz " + tz_icu->getID(id));
1346 } else {
1347 logln(UnicodeString("both java and icu report dst savings of ") + expected + " for tz " + tz_icu->getID(id));
1348 }
1349 delete tz_icu;
1350 }
1351
1352 /**
1353 * Test country code support. Jitterbug 776.
1354 */
1355 void TimeZoneTest::TestCountries() {
1356 // Make sure America/Los_Angeles is in the "US" group, and
1357 // Asia/Tokyo isn't. Vice versa for the "JP" group.
1358 UErrorCode ec = U_ZERO_ERROR;
1359 int32_t n;
1360 StringEnumeration* s = TimeZone::createEnumeration("US");
1361 n = s->count(ec);
1362 UBool la = FALSE, tokyo = FALSE;
1363 UnicodeString laZone("America/Los_Angeles", "");
1364 UnicodeString tokyoZone("Asia/Tokyo", "");
1365 int32_t i;
1366
1367 if (s == NULL || n <= 0) {
1368 errln("FAIL: TimeZone::createEnumeration() returned nothing");
1369 return;
1370 }
1371 for (i=0; i<n; ++i) {
1372 const UnicodeString* id = s->snext(ec);
1373 if (*id == (laZone)) {
1374 la = TRUE;
1375 }
1376 if (*id == (tokyoZone)) {
1377 tokyo = TRUE;
1378 }
1379 }
1380 if (!la || tokyo) {
1381 errln("FAIL: " + laZone + " in US = " + la);
1382 errln("FAIL: " + tokyoZone + " in US = " + tokyo);
1383 }
1384 delete s;
1385
1386 s = TimeZone::createEnumeration("JP");
1387 n = s->count(ec);
1388 la = FALSE; tokyo = FALSE;
1389
1390 for (i=0; i<n; ++i) {
1391 const UnicodeString* id = s->snext(ec);
1392 if (*id == (laZone)) {
1393 la = TRUE;
1394 }
1395 if (*id == (tokyoZone)) {
1396 tokyo = TRUE;
1397 }
1398 }
1399 if (la || !tokyo) {
1400 errln("FAIL: " + laZone + " in JP = " + la);
1401 errln("FAIL: " + tokyoZone + " in JP = " + tokyo);
1402 }
1403 StringEnumeration* s1 = TimeZone::createEnumeration("US");
1404 StringEnumeration* s2 = TimeZone::createEnumeration("US");
1405 for(i=0;i<n;++i){
1406 const UnicodeString* id1 = s1->snext(ec);
1407 if(id1==NULL || U_FAILURE(ec)){
1408 errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n,i);
1409 }
1410 TimeZone* tz1 = TimeZone::createTimeZone(*id1);
1411 for(int j=0; j<n;++j){
1412 const UnicodeString* id2 = s2->snext(ec);
1413 if(id2==NULL || U_FAILURE(ec)){
1414 errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n,i);
1415 }
1416 TimeZone* tz2 = TimeZone::createTimeZone(*id2);
1417 if(tz1->hasSameRules(*tz2)){
1418 logln("ID1 : " + *id1+" == ID2 : " +*id2);
1419 }
1420 delete tz2;
1421 }
1422 delete tz1;
1423 }
1424 delete s1;
1425 delete s2;
1426 delete s;
1427 }
1428
1429 void TimeZoneTest::TestHistorical() {
1430 const int32_t H = U_MILLIS_PER_HOUR;
1431 struct {
1432 const char* id;
1433 int32_t time; // epoch seconds
1434 int32_t offset; // total offset (millis)
1435 } DATA[] = {
1436 // Add transition points (before/after) as desired to test historical
1437 // behavior.
1438 {"America/Los_Angeles", 638963999, -8*H}, // Sun Apr 01 01:59:59 GMT-08:00 1990
1439 {"America/Los_Angeles", 638964000, -7*H}, // Sun Apr 01 03:00:00 GMT-07:00 1990
1440 {"America/Los_Angeles", 657104399, -7*H}, // Sun Oct 28 01:59:59 GMT-07:00 1990
1441 {"America/Los_Angeles", 657104400, -8*H}, // Sun Oct 28 01:00:00 GMT-08:00 1990
1442 {"America/Goose_Bay", -116445601, -4*H}, // Sun Apr 24 01:59:59 GMT-04:00 1966
1443 {"America/Goose_Bay", -116445600, -3*H}, // Sun Apr 24 03:00:00 GMT-03:00 1966
1444 {"America/Goose_Bay", -100119601, -3*H}, // Sun Oct 30 01:59:59 GMT-03:00 1966
1445 {"America/Goose_Bay", -100119600, -4*H}, // Sun Oct 30 01:00:00 GMT-04:00 1966
1446 {"America/Goose_Bay", -84391201, -4*H}, // Sun Apr 30 01:59:59 GMT-04:00 1967
1447 {"America/Goose_Bay", -84391200, -3*H}, // Sun Apr 30 03:00:00 GMT-03:00 1967
1448 {"America/Goose_Bay", -68670001, -3*H}, // Sun Oct 29 01:59:59 GMT-03:00 1967
1449 {"America/Goose_Bay", -68670000, -4*H}, // Sun Oct 29 01:00:00 GMT-04:00 1967
1450 {0, 0, 0}
1451 };
1452
1453 for (int32_t i=0; DATA[i].id!=0; ++i) {
1454 const char* id = DATA[i].id;
1455 TimeZone *tz = TimeZone::createTimeZone(id);
1456 UnicodeString s;
1457 if (tz == 0) {
1458 errln("FAIL: Cannot create %s", id);
1459 } else if (tz->getID(s) != UnicodeString(id)) {
1460 errln((UnicodeString)"FAIL: createTimeZone(" + id + ") => " + s);
1461 } else {
1462 UErrorCode ec = U_ZERO_ERROR;
1463 int32_t raw, dst;
1464 UDate when = (double) DATA[i].time * U_MILLIS_PER_SECOND;
1465 tz->getOffset(when, FALSE, raw, dst, ec);
1466 if (U_FAILURE(ec)) {
1467 errln("FAIL: getOffset");
1468 } else if ((raw+dst) != DATA[i].offset) {
1469 errln((UnicodeString)"FAIL: " + DATA[i].id + ".getOffset(" +
1470 //when + " = " +
1471 dateToString(when) + ") => " +
1472 raw + ", " + dst);
1473 } else {
1474 logln((UnicodeString)"Ok: " + DATA[i].id + ".getOffset(" +
1475 //when + " = " +
1476 dateToString(when) + ") => " +
1477 raw + ", " + dst);
1478 }
1479 }
1480 delete tz;
1481 }
1482 }
1483
1484 void TimeZoneTest::TestEquivalentIDs() {
1485 int32_t n = TimeZone::countEquivalentIDs("PST");
1486 if (n < 2) {
1487 errln((UnicodeString)"FAIL: countEquivalentIDs(PST) = " + n);
1488 } else {
1489 UBool sawLA = FALSE;
1490 for (int32_t i=0; i<n; ++i) {
1491 UnicodeString id = TimeZone::getEquivalentID("PST", i);
1492 logln((UnicodeString)"" + i + " : " + id);
1493 if (id == UnicodeString("America/Los_Angeles")) {
1494 sawLA = TRUE;
1495 }
1496 }
1497 if (!sawLA) {
1498 errln("FAIL: America/Los_Angeles should be in the list");
1499 }
1500 }
1501 }
1502
1503 #endif /* #if !UCONFIG_NO_FORMATTING */