]> git.saurik.com Git - apple/icu.git/blame - icuSources/test/intltest/tztest.cpp
ICU-8.11.1.tar.gz
[apple/icu.git] / icuSources / test / intltest / tztest.cpp
CommitLineData
374ca955 1/***********************************************************************
b75a7d8f 2 * COPYRIGHT:
73c04bcf 3 * Copyright (c) 1997-2006, International Business Machines Corporation
374ca955
A
4 * and others. All Rights Reserved.
5 ***********************************************************************/
b75a7d8f
A
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"
374ca955 19#include "putilimp.h"
b75a7d8f
A
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
33void 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);
374ca955
A
47 CASE(10,TestCountries);
48 CASE(11,TestHistorical);
49 CASE(12,TestEquivalentIDs);
73c04bcf
A
50 CASE(13, TestAliasedNames);
51 CASE(14, TestFractionalDST);
374ca955 52 default: name = ""; break;
b75a7d8f
A
53 }
54}
55
56const int32_t TimeZoneTest::millisPerHour = 3600000;
57
58// ---------------------------------------------------------------------------------
59
60/**
61 * Generic API testing for API coverage.
62 */
63void
64TimeZoneTest::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();
374ca955
A
89 logln((UnicodeString)"TimeZone::createDefault() => " + saveDefault->getID(id));
90 //TimeZone* pstZone = TimeZone::createTimeZone("PST");
b75a7d8f 91
374ca955 92 logln("call uprv_timezone() which uses the host");
b75a7d8f
A
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();
374ca955 97 logln(UnicodeString("Value returned from uprv_timezone = ") + tzoffset);
b75a7d8f
A
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) {
374ca955 108 logln("***** WARNING: If testing in the PST timezone, uprv_timezone should return 28800! *****");
b75a7d8f
A
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;
374ca955 122 //delete pstZone;
b75a7d8f
A
123}
124
125// ---------------------------------------------------------------------------------
126
127/**
128 * Test the setStartRule/setEndRule API calls.
129 */
130void
131TimeZoneTest::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
374ca955
A
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);
b75a7d8f
A
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
203void
374ca955
A
204TimeZoneTest::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
233void
234TimeZoneTest::testUsingBinarySearch(const TimeZone& tz,
235 UDate min, UDate max,
236 UDate expectedBoundary)
b75a7d8f
A
237{
238 UErrorCode status = U_ZERO_ERROR;
374ca955
A
239 UBool startsInDST = tz.inDaylightTime(min, status);
240 if (failure(status, "TimeZone::inDaylightTime")) return;
241 if (tz.inDaylightTime(max, status) == startsInDST) {
b75a7d8f
A
242 logln("Error: inDaylightTime(" + dateToString(max) + ") != " + ((!startsInDST)?"TRUE":"FALSE"));
243 return;
244 }
374ca955 245 if (failure(status, "TimeZone::inDaylightTime")) return;
b75a7d8f
A
246 while ((max - min) > INTERVAL) {
247 UDate mid = (min + max) / 2;
374ca955 248 if (tz.inDaylightTime(mid, status) == startsInDST) {
b75a7d8f 249 min = mid;
374ca955 250 } else {
b75a7d8f
A
251 max = mid;
252 }
374ca955 253 if (failure(status, "TimeZone::inDaylightTime")) return;
b75a7d8f
A
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
268const UDate TimeZoneTest::INTERVAL = 100;
269
270// ---------------------------------------------------------------------------------
271
272// -------------------------------------
273
274/**
275 * Test the offset of the PRT timezone.
276 */
277void
278TimeZoneTest::TestPRTOffset()
279{
280 TimeZone* tz = TimeZone::createTimeZone("PRT");
281 if (tz == 0) {
282 errln("FAIL: TimeZone(PRT) is null");
283 }
284 else {
374ca955
A
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 }
b75a7d8f
A
294 }
295 delete tz;
296}
297
298// -------------------------------------
299
300/**
301 * Regress a specific bug with a sequence of API calls.
302 */
303void
304TimeZoneTest::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 */
332void
333TimeZoneTest::TestGetAvailableIDs913()
334{
335 UErrorCode ec = U_ZERO_ERROR;
374ca955
A
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
b75a7d8f
A
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);
b75a7d8f
A
393 for (i = 0; i < s_length;++i) {
394 if (i > 0) *buf += ", ";
374ca955
A
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 }
b75a7d8f
A
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);
374ca955
A
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) = { ";
b75a7d8f 456
374ca955 457 s = TimeZone::createEnumeration("US");
b75a7d8f
A
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);
374ca955 465
b75a7d8f
A
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/**
374ca955
A
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 *
b75a7d8f
A
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 * [srl - from java - 7/5/1998]
511 * @bug 4130885
512 * Certain short zone IDs, used since 1.1.x, are incorrect.
513 *
514 * The worst of these is:
515 *
516 * "CAT" (Central African Time) should be GMT+2:00, but instead returns a
517 * zone at GMT-1:00. The zone at GMT-1:00 should be called EGT, CVT, EGST,
518 * or AZOST, depending on which zone is meant, but in no case is it CAT.
519 *
520 * Other wrong zone IDs:
521 *
522 * ECT (European Central Time) GMT+1:00: ECT is Ecuador Time,
523 * GMT-5:00. European Central time is abbreviated CEST.
524 *
525 * SST (Solomon Island Time) GMT+11:00. SST is actually Samoa Standard Time,
526 * GMT-11:00. Solomon Island time is SBT.
527 *
528 * NST (New Zealand Time) GMT+12:00. NST is the abbreviation for
529 * Newfoundland Standard Time, GMT-3:30. New Zealanders use NZST.
530 *
531 * AST (Alaska Standard Time) GMT-9:00. [This has already been noted in
532 * another bug.] It should be "AKST". AST is Atlantic Standard Time,
533 * GMT-4:00.
534 *
535 * PNT (Phoenix Time) GMT-7:00. PNT usually means Pitcairn Time,
536 * GMT-8:30. There is no standard abbreviation for Phoenix time, as distinct
537 * from MST with daylight savings.
538 *
539 * In addition to these problems, a number of zones are FAKE. That is, they
540 * don't match what people use in the real world.
541 *
542 * FAKE zones:
543 *
544 * EET (should be EEST)
545 * ART (should be EEST)
546 * MET (should be IRST)
547 * NET (should be AMST)
548 * PLT (should be PKT)
549 * BST (should be BDT)
550 * VST (should be ICT)
551 * CTT (should be CST) +
552 * ACT (should be CST) +
553 * AET (should be EST) +
554 * MIT (should be WST) +
555 * IET (should be EST) +
556 * PRT (should be AST) +
557 * CNT (should be NST)
558 * AGT (should be ARST)
559 * BET (should be EST) +
560 *
561 * + A zone with the correct name already exists and means something
562 * else. E.g., EST usually indicates the US Eastern zone, so it cannot be
563 * used for Brazil (BET).
564 */
565void TimeZoneTest::TestShortZoneIDs()
566{
567 int32_t i;
568 // Create a small struct to hold the array
569 struct
570 {
571 const char *id;
572 int32_t offset;
573 UBool daylight;
574 }
575 kReferenceList [] =
576 {
577 {"MIT", -660, FALSE},
578 {"HST", -600, FALSE},
579 {"AST", -540, TRUE},
580 {"PST", -480, TRUE},
581 {"PNT", -420, FALSE},
374ca955 582 {"MST", -420, FALSE}, // updated Aug 2003 aliu
b75a7d8f 583 {"CST", -360, TRUE},
73c04bcf 584 {"IET", -300, TRUE}, // updated Jan 2006 srl
374ca955 585 {"EST", -300, FALSE}, // updated Aug 2003 aliu
b75a7d8f
A
586 {"PRT", -240, FALSE},
587 {"CNT", -210, TRUE},
588 {"AGT", -180, FALSE}, // updated 26 Sep 2000 aliu
589 {"BET", -180, TRUE},
590 // "CAT", -60, FALSE, // Wrong:
591 // As of bug 4130885, fix CAT (Central Africa)
592 {"CAT", 120, FALSE}, // Africa/Harare
593 {"GMT", 0, FALSE},
594 {"UTC", 0, FALSE}, // ** srl: seems broken in C++
595 {"ECT", 60, TRUE},
596 {"ART", 120, TRUE},
597 {"EET", 120, TRUE},
598 {"EAT", 180, FALSE},
599 {"MET", 60, TRUE}, // updated 12/3/99 aliu
600 {"NET", 240, TRUE}, // updated 12/3/99 aliu
374ca955 601 {"PLT", 300, FALSE}, // updated Aug 2003 aliu
b75a7d8f
A
602 {"IST", 330, FALSE},
603 {"BST", 360, FALSE},
604 {"VST", 420, FALSE},
374ca955 605 {"CTT", 480, FALSE}, // updated Aug 2003 aliu
b75a7d8f 606 {"JST", 540, FALSE},
374ca955 607 {"ACT", 570, FALSE}, // updated Aug 2003 aliu
b75a7d8f
A
608 {"AET", 600, TRUE},
609 {"SST", 660, FALSE},
610 // "NST", 720, FALSE,
611 // As of bug 4130885, fix NST (New Zealand)
612 {"NST", 720, TRUE}, // Pacific/Auckland
613 {"",0,FALSE}
614 };
615
616
617 for(i=0;kReferenceList[i].id[0];i++) {
618 UnicodeString itsID(kReferenceList[i].id);
619 UBool ok = TRUE;
620 // Check existence.
621 TimeZone *tz = TimeZone::createTimeZone(itsID);
622 if (!tz) {
623 errln("FAIL: Time Zone " + itsID + " does not exist!");
624 continue;
625 }
626
627 // Check daylight usage.
628 UBool usesDaylight = tz->useDaylightTime();
629 if (usesDaylight != kReferenceList[i].daylight) {
630 errln("FAIL: Time Zone " + itsID + " use daylight is " +
631 (usesDaylight?"TRUE":"FALSE") +
632 " but it should be " +
633 ((kReferenceList[i].daylight)?"TRUE":"FALSE"));
634 ok = FALSE;
635 }
636
637 // Check offset
638 int32_t offsetInMinutes = tz->getRawOffset()/60000;
639 if (offsetInMinutes != kReferenceList[i].offset) {
640 errln("FAIL: Time Zone " + itsID + " raw offset is " +
641 offsetInMinutes +
642 " but it should be " + kReferenceList[i].offset);
643 ok = FALSE;
644 }
645
646 if (ok) {
647 logln("OK: " + itsID +
648 " useDaylightTime() & getRawOffset() as expected");
649 }
650 delete tz;
651 }
652
653
654 // OK now test compat
655 logln("Testing for compatibility zones");
656
657 const char* compatibilityMap[] = {
658 // This list is copied from tz.alias. If tz.alias
374ca955 659 // changes, this list must be updated. Current as of Aug 2003
b75a7d8f
A
660 "ACT", "Australia/Darwin",
661 "AET", "Australia/Sydney",
662 "AGT", "America/Buenos_Aires",
663 "ART", "Africa/Cairo",
664 "AST", "America/Anchorage",
665 "BET", "America/Sao_Paulo",
666 "BST", "Asia/Dhaka", // Spelling changed in 2000h
667 "CAT", "Africa/Harare",
668 "CNT", "America/St_Johns",
669 "CST", "America/Chicago",
670 "CTT", "Asia/Shanghai",
671 "EAT", "Africa/Addis_Ababa",
672 "ECT", "Europe/Paris",
673 // EET Europe/Istanbul # EET is a standard UNIX zone
374ca955 674 // "EST", "America/New_York", # EST is an Olson alias now (2003)
b75a7d8f
A
675 "HST", "Pacific/Honolulu",
676 "IET", "America/Indianapolis",
677 "IST", "Asia/Calcutta",
678 "JST", "Asia/Tokyo",
679 // MET Asia/Tehran # MET is a standard UNIX zone
680 "MIT", "Pacific/Apia",
374ca955 681 // "MST", "America/Denver", # MST is an Olson alias now (2003)
b75a7d8f
A
682 "NET", "Asia/Yerevan",
683 "NST", "Pacific/Auckland",
684 "PLT", "Asia/Karachi",
685 "PNT", "America/Phoenix",
686 "PRT", "America/Puerto_Rico",
687 "PST", "America/Los_Angeles",
688 "SST", "Pacific/Guadalcanal",
689 "UTC", "Etc/GMT",
690 "VST", "Asia/Saigon",
691 "","",""
692 };
693
694 for (i=0;*compatibilityMap[i];i+=2) {
695 UnicodeString itsID;
696
697 const char *zone1 = compatibilityMap[i];
698 const char *zone2 = compatibilityMap[i+1];
699
700 TimeZone *tz1 = TimeZone::createTimeZone(zone1);
701 TimeZone *tz2 = TimeZone::createTimeZone(zone2);
702
703 if (!tz1) {
704 errln(UnicodeString("FAIL: Could not find short ID zone ") + zone1);
705 }
706 if (!tz2) {
707 errln(UnicodeString("FAIL: Could not find long ID zone ") + zone2);
708 }
709
710 if (tz1 && tz2) {
711 // make NAME same so comparison will only look at the rest
712 tz2->setID(tz1->getID(itsID));
713
714 if (*tz1 != *tz2) {
715 errln("FAIL: " + UnicodeString(zone1) +
716 " != " + UnicodeString(zone2));
717 } else {
718 logln("OK: " + UnicodeString(zone1) +
719 " == " + UnicodeString(zone2));
720 }
721 }
722
723 delete tz1;
724 delete tz2;
725 }
726}
727
728/**
729 * Utility function for TestCustomParse
730 */
731UnicodeString& TimeZoneTest::formatMinutes(int32_t min, UnicodeString& rv)
732{
733 rv.remove();
734
735 char sign = '+';
736 if (min < 0) { sign = '-'; min = -min; }
737 int h = min/60;
738 min = min%60;
739
740 rv += UChar(sign);
741 if(h > 10)
742 rv += UChar(0x0030 + (h/10));
743 rv += UChar(0x0030 + (h%10));
744
745 rv += ":";
746
747 if(min > 10)
748 rv += UChar(0x0030 + (min/10));
749 else
750 rv += "0";
751
752 rv += UChar(0x0030 + (min%10));
753
754 return rv;
755}
756
757
758/**
759 * As part of the VM fix (see CCC approved RFE 4028006, bug
760 * 4044013), TimeZone.getTimeZone() has been modified to recognize
761 * generic IDs of the form GMT[+-]hh:mm, GMT[+-]hhmm, and
762 * GMT[+-]hh. Test this behavior here.
763 *
764 * @bug 4044013
765 */
766void TimeZoneTest::TestCustomParse()
767{
768 int32_t i;
769 const int32_t kUnparseable = 604800; // the number of seconds in a week. More than any offset should be.
770 const UnicodeString kExpectedCustomID = "Custom";
771
772 struct
773 {
774 const char *customId;
775 int32_t expectedOffset;
776 }
777 kData[] =
778 {
779 // ID Expected offset in minutes
73c04bcf 780 //{"GMT", kUnparseable}, //Isn't custom. Can't test it here. [returns normal GMT]
b75a7d8f 781 {"GMT-YOUR.AD.HERE", kUnparseable},
374ca955
A
782 // {"GMT0", kUnparseable}, // ICU 2.8: An Olson zone ID
783 // {"GMT+0", (0)}, // ICU 2.8: An Olson zone ID
b75a7d8f
A
784 {"GMT+1", (60)},
785 {"GMT-0030", (-30)},
786 {"GMT+15:99", (15*60+99)},
787 {"GMT+", kUnparseable},
788 {"GMT-", kUnparseable},
789 {"GMT+0:", kUnparseable},
790 {"GMT-:", kUnparseable},
791 {"GMT-YOUR.AD.HERE", kUnparseable},
792 {"GMT+0010", (10)}, // Interpret this as 00:10
793 {"GMT-10", (-10*60)},
794 {"GMT+30", (30)},
795 {"GMT-3:30", (-(3*60+30))},
796 {"GMT-230", (-(2*60+30))},
797 {0, 0}
798 };
799
800 for (i=0; kData[i].customId != 0; i++)
801 {
802 UnicodeString id(kData[i].customId);
803 int32_t exp = kData[i].expectedOffset;
73c04bcf
A
804/*
805 { // for no data test Jitterbug 4354
806 UErrorCode success = U_ZERO_ERROR;
807 NumberFormat* numberFormat = NumberFormat::createInstance(success);
808 if (U_FAILURE(success)) {
809 dataerrln(" NumberFormat::createInstance() error");
810 return;
811 }
812 delete numberFormat;
813 }
814 */
b75a7d8f
A
815
816 TimeZone *zone = TimeZone::createTimeZone(id);
817 UnicodeString itsID, temp;
818
819 logln();
820 logln("testing # " + formatMinutes(i, temp) + id);
821
822 /*
823 if(zone == NULL)
824 {
825 errln("FAIL: Could not createTimeZone(" + id + "). Returned NULL.");
826 continue;
827 }
828 */
829
830
831 if (! zone->getID(itsID).compare("GMT"))
832 //if(zone == NULL)
833 {
834 logln(id + " -> generic GMT");
835 // When TimeZone.getTimeZone() can't parse the id, it
836 // returns GMT -- a dubious practice, but required for
837 // backward compatibility.
838 if (exp != kUnparseable) {
839 errln("FAIL: Expected offset of " + formatMinutes(exp,temp) +
840 " for " + id + ", got parse failure");
841 }
842 }
843 else
844 {
845 zone->getID(itsID);
846 int32_t ioffset = zone->getRawOffset()/60000;
847 UnicodeString offset;
848 formatMinutes(ioffset, offset);
849 logln(id + " -> " + itsID + " GMT" + offset);
850 if (exp == kUnparseable)
851 {
852 errln("FAIL: Expected parse failure for " + id +
853 ", got offset of " + offset +
854 ", id " + itsID);
855 }
856 else if (ioffset != exp ||
857 (itsID.compare(kExpectedCustomID) != 0))
858 {
859 errln("Expected offset of " + formatMinutes(exp,temp) +
860 ", id Custom, for " + id +
861 ", got offset of " + offset +
862 ", id " + itsID);
863 }
864 }
865 delete zone;
866 }
867}
868
73c04bcf
A
869static const UVersionInfo ICU_37 = {3,7,0,0};
870
871void
872TimeZoneTest::TestAliasedNames()
873{
874 struct {
875 const char *from;
876 const char *to;
877 } kData[] = {
878 /* Generated by org.unicode.cldr.tool.CountItems */
879
880 /* zoneID, canonical zoneID */
881 {"Africa/Timbuktu", "Africa/Bamako"},
882 {"America/Argentina/Buenos_Aires", "America/Buenos_Aires"},
883 {"America/Argentina/Catamarca", "America/Catamarca"},
884 {"America/Argentina/ComodRivadavia", "America/Catamarca"},
885 {"America/Argentina/Cordoba", "America/Cordoba"},
886 {"America/Argentina/Jujuy", "America/Jujuy"},
887 {"America/Argentina/Mendoza", "America/Mendoza"},
888 {"America/Atka", "America/Adak"},
889 {"America/Ensenada", "America/Tijuana"},
890 {"America/Fort_Wayne", "America/Indiana/Indianapolis"},
891 {"America/Indianapolis", "America/Indiana/Indianapolis"},
892 {"America/Knox_IN", "America/Indiana/Knox"},
893 {"America/Louisville", "America/Kentucky/Louisville"},
894 {"America/Porto_Acre", "America/Rio_Branco"},
895 {"America/Rosario", "America/Cordoba"},
896 {"America/Virgin", "America/St_Thomas"},
897 {"Asia/Ashkhabad", "Asia/Ashgabat"},
898 {"Asia/Chungking", "Asia/Chongqing"},
899 {"Asia/Dacca", "Asia/Dhaka"},
900 {"Asia/Istanbul", "Europe/Istanbul"},
901 {"Asia/Macao", "Asia/Macau"},
902 {"Asia/Tel_Aviv", "Asia/Jerusalem"},
903 {"Asia/Thimbu", "Asia/Thimphu"},
904 {"Asia/Ujung_Pandang", "Asia/Makassar"},
905 {"Asia/Ulan_Bator", "Asia/Ulaanbaatar"},
906 {"Australia/ACT", "Australia/Sydney"},
907 {"Australia/Canberra", "Australia/Sydney"},
908 {"Australia/LHI", "Australia/Lord_Howe"},
909 {"Australia/NSW", "Australia/Sydney"},
910 {"Australia/North", "Australia/Darwin"},
911 {"Australia/Queensland", "Australia/Brisbane"},
912 {"Australia/South", "Australia/Adelaide"},
913 {"Australia/Tasmania", "Australia/Hobart"},
914 {"Australia/Victoria", "Australia/Melbourne"},
915 {"Australia/West", "Australia/Perth"},
916 {"Australia/Yancowinna", "Australia/Broken_Hill"},
917 {"Brazil/Acre", "America/Rio_Branco"},
918 {"Brazil/DeNoronha", "America/Noronha"},
919 {"Brazil/East", "America/Sao_Paulo"},
920 {"Brazil/West", "America/Manaus"},
921 {"Canada/Atlantic", "America/Halifax"},
922 {"Canada/Central", "America/Winnipeg"},
923 {"Canada/East-Saskatchewan", "America/Regina"},
924 {"Canada/Eastern", "America/Toronto"},
925 {"Canada/Mountain", "America/Edmonton"},
926 {"Canada/Newfoundland", "America/St_Johns"},
927 {"Canada/Pacific", "America/Vancouver"},
928 {"Canada/Saskatchewan", "America/Regina"},
929 {"Canada/Yukon", "America/Whitehorse"},
930 {"Chile/Continental", "America/Santiago"},
931 {"Chile/EasterIsland", "Pacific/Easter"},
932 {"Cuba", "America/Havana"},
933 {"Egypt", "Africa/Cairo"},
934 {"Eire", "Europe/Dublin"},
935 {"Etc/GMT+0", "Etc/GMT"},
936 {"Etc/GMT-0", "Etc/GMT"},
937 {"Etc/GMT0", "Etc/GMT"},
938 {"Etc/Greenwich", "Etc/GMT"},
939 {"Etc/UCT", "Etc/GMT"},
940 {"Etc/UTC", "Etc/GMT"},
941 {"Etc/Universal", "Etc/GMT"},
942 {"Etc/Zulu", "Etc/GMT"},
943 {"Europe/Belfast", "Europe/London"},
944 {"Europe/Nicosia", "Asia/Nicosia"},
945 {"Europe/Tiraspol", "Europe/Chisinau"},
946 {"GB", "Europe/London"},
947 {"GB-Eire", "Europe/London"},
948 {"GMT", "Etc/GMT"},
949 {"GMT+0", "Etc/GMT"},
950 {"GMT-0", "Etc/GMT"},
951 {"GMT0", "Etc/GMT"},
952 {"Greenwich", "Etc/GMT"},
953 {"Hongkong", "Asia/Hong_Kong"},
954 {"Iceland", "Atlantic/Reykjavik"},
955 {"Iran", "Asia/Tehran"},
956 {"Israel", "Asia/Jerusalem"},
957 {"Jamaica", "America/Jamaica"},
958 {"Japan", "Asia/Tokyo"},
959 {"Kwajalein", "Pacific/Kwajalein"},
960 {"Libya", "Africa/Tripoli"},
961 {"Mexico/BajaNorte", "America/Tijuana"},
962 {"Mexico/BajaSur", "America/Mazatlan"},
963 {"Mexico/General", "America/Mexico_City"},
964 {"NZ", "Pacific/Auckland"},
965 {"NZ-CHAT", "Pacific/Chatham"},
966 {"Navajo", "America/Shiprock"},
967 {"PRC", "Asia/Shanghai"},
968 {"Pacific/Samoa", "Pacific/Pago_Pago"},
969 {"Pacific/Yap", "Pacific/Truk"},
970 {"Poland", "Europe/Warsaw"},
971 {"Portugal", "Europe/Lisbon"},
972 {"ROC", "Asia/Taipei"},
973 {"ROK", "Asia/Seoul"},
974 {"Singapore", "Asia/Singapore"},
975 {"Turkey", "Europe/Istanbul"},
976 {"UCT", "Etc/GMT"},
977 {"US/Alaska", "America/Anchorage"},
978 {"US/Aleutian", "America/Adak"},
979 {"US/Arizona", "America/Phoenix"},
980 {"US/Central", "America/Chicago"},
981 {"US/East-Indiana", "America/Indiana/Indianapolis"},
982 {"US/Eastern", "America/New_York"},
983 {"US/Hawaii", "Pacific/Honolulu"},
984 {"US/Indiana-Starke", "America/Indiana/Knox"},
985 {"US/Michigan", "America/Detroit"},
986 {"US/Mountain", "America/Denver"},
987 {"US/Pacific", "America/Los_Angeles"},
988 {"US/Pacific-New", "America/Los_Angeles"},
989 {"US/Samoa", "Pacific/Pago_Pago"},
990 {"UTC", "Etc/GMT"},
991 {"Universal", "Etc/GMT"},
992 {"W-SU", "Europe/Moscow"},
993 {"Zulu", "Etc/GMT"},
994 /* Total: 113 */
995
996 };
997
998 TimeZone::EDisplayType styles[] = { TimeZone::SHORT, TimeZone::LONG };
999 UBool useDst[] = { FALSE, TRUE };
1000 int32_t noLoc = uloc_countAvailable();
1001
1002 if(isICUVersionAtLeast(ICU_37)) {
1003 errln("This test needs to be fixed. This test fails in exhaustive mode because we need to implement generic timezones.\n");
1004 }
1005
1006 int32_t i, j, k, loc;
1007 UnicodeString fromName, toName;
1008 TimeZone *from = NULL, *to = NULL;
1009 for(i = 0; i < (int32_t)(sizeof(kData)/sizeof(kData[0])); i++) {
1010 from = TimeZone::createTimeZone(kData[i].from);
1011 to = TimeZone::createTimeZone(kData[i].to);
1012 if(!from->hasSameRules(*to)) {
1013 errln("different at %i\n", i);
1014 }
1015 if(!quick && isICUVersionAtLeast(ICU_37)) {
1016 errln("This test needs to be fixed. This test fails in exhaustive mode because we need to implement generic timezones.\n");
1017 for(loc = 0; loc < noLoc; loc++) {
1018 const char* locale = uloc_getAvailable(loc);
1019 for(j = 0; j < (int32_t)(sizeof(styles)/sizeof(styles[0])); j++) {
1020 for(k = 0; k < (int32_t)(sizeof(useDst)/sizeof(useDst[0])); k++) {
1021 fromName.remove();
1022 toName.remove();
1023 from->getDisplayName(useDst[k], styles[j],locale, fromName);
1024 to->getDisplayName(useDst[k], styles[j], locale, toName);
1025 if(fromName.compare(toName) != 0) {
1026 errln("Fail: Expected "+toName+" but got " + prettify(fromName)
1027 + " for locale: " + locale + " index: "+ loc
1028 + " to id "+ kData[i].to
1029 + " from id " + kData[i].from);
1030 }
1031 }
1032 }
1033 }
1034 } else {
1035 fromName.remove();
1036 toName.remove();
1037 from->getDisplayName(fromName);
1038 to->getDisplayName(toName);
1039 if(fromName.compare(toName) != 0) {
1040 errln("Fail: Expected "+toName+" but got " + fromName);
1041 }
1042 }
1043 delete from;
1044 delete to;
1045 }
1046}
1047
b75a7d8f
A
1048/**
1049 * Test the basic functionality of the getDisplayName() API.
1050 *
1051 * @bug 4112869
1052 * @bug 4028006
1053 *
1054 * See also API change request A41.
1055 *
1056 * 4/21/98 - make smarter, so the test works if the ext resources
1057 * are present or not.
1058 */
1059void
1060TimeZoneTest::TestDisplayName()
1061{
1062 UErrorCode status = U_ZERO_ERROR;
1063 int32_t i;
1064 TimeZone *zone = TimeZone::createTimeZone("PST");
1065 UnicodeString name;
1066 zone->getDisplayName(Locale::getEnglish(), name);
1067 logln("PST->" + name);
1068 if (name.compare("Pacific Standard Time") != 0)
1069 errln("Fail: Expected \"Pacific Standard Time\" but got " + name);
1070
1071 //*****************************************************************
1072 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
1073 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
1074 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
1075 //*****************************************************************
1076 struct
1077 {
1078 UBool useDst;
1079 TimeZone::EDisplayType style;
1080 const char *expect;
1081 } kData[] = {
1082 {FALSE, TimeZone::SHORT, "PST"},
1083 {TRUE, TimeZone::SHORT, "PDT"},
1084 {FALSE, TimeZone::LONG, "Pacific Standard Time"},
1085 {TRUE, TimeZone::LONG, "Pacific Daylight Time"},
1086
1087 {FALSE, TimeZone::LONG, ""}
1088 };
1089
1090 for (i=0; kData[i].expect[0] != '\0'; i++)
1091 {
1092 name.remove();
1093 name = zone->getDisplayName(kData[i].useDst,
1094 kData[i].style,
1095 Locale::getEnglish(), name);
1096 if (name.compare(kData[i].expect) != 0)
1097 errln("Fail: Expected " + UnicodeString(kData[i].expect) + "; got " + name);
1098 logln("PST [with options]->" + name);
1099 }
374ca955
A
1100 for (i=0; kData[i].expect[0] != '\0'; i++)
1101 {
b75a7d8f
A
1102 name.remove();
1103 name = zone->getDisplayName(kData[i].useDst,
1104 kData[i].style, name);
1105 if (name.compare(kData[i].expect) != 0)
1106 errln("Fail: Expected " + UnicodeString(kData[i].expect) + "; got " + name);
1107 logln("PST [with options]->" + name);
1108 }
1109
1110
1111 // Make sure that we don't display the DST name by constructing a fake
1112 // PST zone that has DST all year long.
1113 SimpleTimeZone *zone2 = new SimpleTimeZone(0, "PST");
1114
1115 zone2->setStartRule(UCAL_JANUARY, 1, 0, 0, status);
1116 zone2->setEndRule(UCAL_DECEMBER, 31, 0, 0, status);
1117
374ca955
A
1118 UnicodeString inDaylight;
1119 if (zone2->inDaylightTime(UDate(0), status)) {
1120 inDaylight = UnicodeString("TRUE");
1121 } else {
1122 inDaylight = UnicodeString("FALSE");
1123 }
b75a7d8f
A
1124 logln(UnicodeString("Modified PST inDaylightTime->") + inDaylight );
1125 if(U_FAILURE(status))
1126 {
1127 errln("Some sort of error..." + UnicodeString(u_errorName(status))); // REVISIT
1128 }
1129 name.remove();
1130 name = zone2->getDisplayName(Locale::getEnglish(),name);
1131 logln("Modified PST->" + name);
1132 if (name.compare("Pacific Standard Time") != 0)
1133 errln("Fail: Expected \"Pacific Standard Time\"");
1134
1135 // Make sure we get the default display format for Locales
1136 // with no display name data.
374ca955 1137 Locale mt_MT("mt_MT");
b75a7d8f 1138 name.remove();
374ca955 1139 name = zone->getDisplayName(mt_MT,name);
b75a7d8f
A
1140 //*****************************************************************
1141 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
1142 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
1143 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
1144 //*****************************************************************
374ca955 1145 logln("PST(mt_MT)->" + name);
b75a7d8f
A
1146
1147 // *** REVISIT SRL how in the world do I check this? looks java specific.
1148 // Now be smart -- check to see if zh resource is even present.
1149 // If not, we expect the en fallback behavior.
374ca955 1150 ResourceBundle enRB(NULL,
b75a7d8f
A
1151 Locale::getEnglish(), status);
1152 if(U_FAILURE(status))
1153 errln("Couldn't get ResourceBundle for en");
1154
374ca955
A
1155 ResourceBundle mtRB(NULL,
1156 mt_MT, status);
b75a7d8f 1157 //if(U_FAILURE(status))
374ca955 1158 // errln("Couldn't get ResourceBundle for mt_MT");
b75a7d8f
A
1159
1160 UBool noZH = U_FAILURE(status);
1161
1162 if (noZH) {
374ca955 1163 logln("Warning: Not testing the mt_MT behavior because resource is absent");
b75a7d8f
A
1164 if (name != "Pacific Standard Time")
1165 errln("Fail: Expected Pacific Standard Time");
1166 }
1167
1168
1169 if (name.compare("GMT-08:00") &&
1170 name.compare("GMT-8:00") &&
1171 name.compare("GMT-0800") &&
1172 name.compare("GMT-800")) {
374ca955 1173 errln(UnicodeString("Fail: Expected GMT-08:00 or something similar for PST in mt_MT but got ") + name );
b75a7d8f
A
1174 errln("************************************************************");
1175 errln("THE ABOVE FAILURE MAY JUST MEAN THE LOCALE DATA HAS CHANGED");
1176 errln("************************************************************");
1177 }
1178
1179 // Now try a non-existent zone
1180 delete zone2;
1181 zone2 = new SimpleTimeZone(90*60*1000, "xyzzy");
1182 name.remove();
1183 name = zone2->getDisplayName(Locale::getEnglish(),name);
1184 logln("GMT+90min->" + name);
1185 if (name.compare("GMT+01:30") &&
1186 name.compare("GMT+1:30") &&
1187 name.compare("GMT+0130") &&
1188 name.compare("GMT+130"))
1189 errln("Fail: Expected GMT+01:30 or something similar");
374ca955 1190 name.truncate(0);
b75a7d8f
A
1191 zone2->getDisplayName(name);
1192 logln("GMT+90min->" + name);
1193 if (name.compare("GMT+01:30") &&
1194 name.compare("GMT+1:30") &&
1195 name.compare("GMT+0130") &&
1196 name.compare("GMT+130"))
1197 errln("Fail: Expected GMT+01:30 or something similar");
1198 // clean up
1199 delete zone;
1200 delete zone2;
1201}
1202
1203/**
1204 * @bug 4107276
1205 */
1206void
1207TimeZoneTest::TestDSTSavings()
1208{
1209 UErrorCode status = U_ZERO_ERROR;
1210 // It might be better to find a way to integrate this test into the main TimeZone
1211 // tests above, but I don't have time to figure out how to do this (or if it's
1212 // even really a good idea). Let's consider that a future. --rtg 1/27/98
1213 SimpleTimeZone *tz = new SimpleTimeZone(-5 * U_MILLIS_PER_HOUR, "dstSavingsTest",
1214 UCAL_MARCH, 1, 0, 0, UCAL_SEPTEMBER, 1, 0, 0,
1215 (int32_t)(0.5 * U_MILLIS_PER_HOUR), status);
1216 if(U_FAILURE(status))
1217 errln("couldn't create TimeZone");
1218
1219 if (tz->getRawOffset() != -5 * U_MILLIS_PER_HOUR)
1220 errln(UnicodeString("Got back a raw offset of ") + (tz->getRawOffset() / U_MILLIS_PER_HOUR) +
1221 " hours instead of -5 hours.");
1222 if (!tz->useDaylightTime())
1223 errln("Test time zone should use DST but claims it doesn't.");
1224 if (tz->getDSTSavings() != 0.5 * U_MILLIS_PER_HOUR)
1225 errln(UnicodeString("Set DST offset to 0.5 hour, but got back ") + (tz->getDSTSavings() /
1226 U_MILLIS_PER_HOUR) + " hours instead.");
1227
1228 int32_t offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JANUARY, 1,
1229 UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status);
1230 if (offset != -5 * U_MILLIS_PER_HOUR)
1231 errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ")
1232 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1233
1234 offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JUNE, 1, UCAL_MONDAY,
1235 10 * U_MILLIS_PER_HOUR,status);
1236 if (offset != -4.5 * U_MILLIS_PER_HOUR)
1237 errln(UnicodeString("The offset for 10 AM, 6/1/98 should have been -4.5 hours, but we got ")
1238 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1239
1240 tz->setDSTSavings(U_MILLIS_PER_HOUR, status);
1241 offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JANUARY, 1,
1242 UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status);
1243 if (offset != -5 * U_MILLIS_PER_HOUR)
1244 errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ")
1245 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1246
1247 offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JUNE, 1, UCAL_MONDAY,
1248 10 * U_MILLIS_PER_HOUR,status);
1249 if (offset != -4 * U_MILLIS_PER_HOUR)
1250 errln(UnicodeString("The offset for 10 AM, 6/1/98 (with a 1-hour DST offset) should have been -4 hours, but we got ")
1251 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1252
1253 delete tz;
1254}
1255
1256/**
1257 * @bug 4107570
1258 */
1259void
1260TimeZoneTest::TestAlternateRules()
1261{
1262 // Like TestDSTSavings, this test should probably be integrated somehow with the main
1263 // test at the top of this class, but I didn't have time to figure out how to do that.
1264 // --rtg 1/28/98
1265
1266 SimpleTimeZone tz(-5 * U_MILLIS_PER_HOUR, "alternateRuleTest");
1267
1268 // test the day-of-month API
1269 UErrorCode status = U_ZERO_ERROR;
1270 tz.setStartRule(UCAL_MARCH, 10, 12 * U_MILLIS_PER_HOUR, status);
1271 if(U_FAILURE(status))
1272 errln("tz.setStartRule failed");
1273 tz.setEndRule(UCAL_OCTOBER, 20, 12 * U_MILLIS_PER_HOUR, status);
1274 if(U_FAILURE(status))
1275 errln("tz.setStartRule failed");
1276
1277 int32_t offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 5,
1278 UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status);
1279 if (offset != -5 * U_MILLIS_PER_HOUR)
1280 errln(UnicodeString("The offset for 10AM, 3/5/98 should have been -5 hours, but we got ")
1281 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1282
1283 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 15,
1284 UCAL_SUNDAY, 10 * millisPerHour,status);
1285 if (offset != -4 * U_MILLIS_PER_HOUR)
1286 errln(UnicodeString("The offset for 10AM, 3/15/98 should have been -4 hours, but we got ")
1287 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1288
1289 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 15,
1290 UCAL_THURSDAY, 10 * millisPerHour,status);
1291 if (offset != -4 * U_MILLIS_PER_HOUR)
1292 errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ") + (offset / U_MILLIS_PER_HOUR) + " hours.");
1293
1294 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 25,
1295 UCAL_SUNDAY, 10 * millisPerHour,status);
1296 if (offset != -5 * U_MILLIS_PER_HOUR)
1297 errln(UnicodeString("The offset for 10AM, 10/25/98 should have been -5 hours, but we got ")
1298 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1299
1300 // test the day-of-week-after-day-in-month API
1301 tz.setStartRule(UCAL_MARCH, 10, UCAL_FRIDAY, 12 * millisPerHour, TRUE, status);
1302 if(U_FAILURE(status))
1303 errln("tz.setStartRule failed");
1304 tz.setEndRule(UCAL_OCTOBER, 20, UCAL_FRIDAY, 12 * millisPerHour, FALSE, status);
1305 if(U_FAILURE(status))
1306 errln("tz.setStartRule failed");
1307
1308 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 11,
1309 UCAL_WEDNESDAY, 10 * millisPerHour,status);
1310 if (offset != -5 * U_MILLIS_PER_HOUR)
1311 errln(UnicodeString("The offset for 10AM, 3/11/98 should have been -5 hours, but we got ")
1312 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1313
1314 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 14,
1315 UCAL_SATURDAY, 10 * millisPerHour,status);
1316 if (offset != -4 * U_MILLIS_PER_HOUR)
1317 errln(UnicodeString("The offset for 10AM, 3/14/98 should have been -4 hours, but we got ")
1318 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1319
1320 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 15,
1321 UCAL_THURSDAY, 10 * millisPerHour,status);
1322 if (offset != -4 * U_MILLIS_PER_HOUR)
1323 errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ")
1324 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1325
1326 offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 17,
1327 UCAL_SATURDAY, 10 * millisPerHour,status);
1328 if (offset != -5 * U_MILLIS_PER_HOUR)
1329 errln(UnicodeString("The offset for 10AM, 10/17/98 should have been -5 hours, but we got ")
1330 + (offset / U_MILLIS_PER_HOUR) + " hours.");
1331}
1332
73c04bcf
A
1333void TimeZoneTest::TestFractionalDST() {
1334 const char* tzName = "Australia/Lord_Howe"; // 30 min offset
1335 TimeZone* tz_icu = TimeZone::createTimeZone(tzName);
1336 int dst_icu = tz_icu->getDSTSavings();
1337 UnicodeString id;
1338 int32_t expected = 1800000;
1339 if (expected != dst_icu) {
1340 errln(UnicodeString("java reports dst savings of ") + expected +
1341 " but icu reports " + dst_icu +
1342 " for tz " + tz_icu->getID(id));
1343 } else {
1344 logln(UnicodeString("both java and icu report dst savings of ") + expected + " for tz " + tz_icu->getID(id));
1345 }
1346 delete tz_icu;
1347}
1348
b75a7d8f
A
1349/**
1350 * Test country code support. Jitterbug 776.
1351 */
1352void TimeZoneTest::TestCountries() {
1353 // Make sure America/Los_Angeles is in the "US" group, and
1354 // Asia/Tokyo isn't. Vice versa for the "JP" group.
1355 UErrorCode ec = U_ZERO_ERROR;
1356 int32_t n;
1357 StringEnumeration* s = TimeZone::createEnumeration("US");
1358 n = s->count(ec);
1359 UBool la = FALSE, tokyo = FALSE;
1360 UnicodeString laZone("America/Los_Angeles", "");
1361 UnicodeString tokyoZone("Asia/Tokyo", "");
1362 int32_t i;
1363
1364 if (s == NULL || n <= 0) {
1365 errln("FAIL: TimeZone::createEnumeration() returned nothing");
1366 return;
1367 }
1368 for (i=0; i<n; ++i) {
1369 const UnicodeString* id = s->snext(ec);
1370 if (*id == (laZone)) {
1371 la = TRUE;
1372 }
1373 if (*id == (tokyoZone)) {
1374 tokyo = TRUE;
1375 }
1376 }
1377 if (!la || tokyo) {
1378 errln("FAIL: " + laZone + " in US = " + la);
1379 errln("FAIL: " + tokyoZone + " in US = " + tokyo);
1380 }
1381 delete s;
1382
1383 s = TimeZone::createEnumeration("JP");
1384 n = s->count(ec);
1385 la = FALSE; tokyo = FALSE;
1386
1387 for (i=0; i<n; ++i) {
1388 const UnicodeString* id = s->snext(ec);
1389 if (*id == (laZone)) {
1390 la = TRUE;
1391 }
1392 if (*id == (tokyoZone)) {
1393 tokyo = TRUE;
1394 }
1395 }
1396 if (la || !tokyo) {
1397 errln("FAIL: " + laZone + " in JP = " + la);
1398 errln("FAIL: " + tokyoZone + " in JP = " + tokyo);
1399 }
374ca955
A
1400 StringEnumeration* s1 = TimeZone::createEnumeration("US");
1401 StringEnumeration* s2 = TimeZone::createEnumeration("US");
1402 for(i=0;i<n;++i){
1403 const UnicodeString* id1 = s1->snext(ec);
1404 if(id1==NULL || U_FAILURE(ec)){
1405 errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n,i);
1406 }
1407 TimeZone* tz1 = TimeZone::createTimeZone(*id1);
1408 for(int j=0; j<n;++j){
1409 const UnicodeString* id2 = s2->snext(ec);
1410 if(id2==NULL || U_FAILURE(ec)){
1411 errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n,i);
1412 }
1413 TimeZone* tz2 = TimeZone::createTimeZone(*id2);
1414 if(tz1->hasSameRules(*tz2)){
1415 logln("ID1 : " + *id1+" == ID2 : " +*id2);
1416 }
1417 delete tz2;
1418 }
1419 delete tz1;
1420 }
1421 delete s1;
1422 delete s2;
b75a7d8f
A
1423 delete s;
1424}
1425
374ca955
A
1426void TimeZoneTest::TestHistorical() {
1427 const int32_t H = U_MILLIS_PER_HOUR;
1428 struct {
1429 const char* id;
1430 int32_t time; // epoch seconds
1431 int32_t offset; // total offset (millis)
1432 } DATA[] = {
1433 // Add transition points (before/after) as desired to test historical
1434 // behavior.
1435 {"America/Los_Angeles", 638963999, -8*H}, // Sun Apr 01 01:59:59 GMT-08:00 1990
1436 {"America/Los_Angeles", 638964000, -7*H}, // Sun Apr 01 03:00:00 GMT-07:00 1990
1437 {"America/Los_Angeles", 657104399, -7*H}, // Sun Oct 28 01:59:59 GMT-07:00 1990
1438 {"America/Los_Angeles", 657104400, -8*H}, // Sun Oct 28 01:00:00 GMT-08:00 1990
1439 {"America/Goose_Bay", -116445601, -4*H}, // Sun Apr 24 01:59:59 GMT-04:00 1966
1440 {"America/Goose_Bay", -116445600, -3*H}, // Sun Apr 24 03:00:00 GMT-03:00 1966
1441 {"America/Goose_Bay", -100119601, -3*H}, // Sun Oct 30 01:59:59 GMT-03:00 1966
1442 {"America/Goose_Bay", -100119600, -4*H}, // Sun Oct 30 01:00:00 GMT-04:00 1966
1443 {"America/Goose_Bay", -84391201, -4*H}, // Sun Apr 30 01:59:59 GMT-04:00 1967
1444 {"America/Goose_Bay", -84391200, -3*H}, // Sun Apr 30 03:00:00 GMT-03:00 1967
1445 {"America/Goose_Bay", -68670001, -3*H}, // Sun Oct 29 01:59:59 GMT-03:00 1967
1446 {"America/Goose_Bay", -68670000, -4*H}, // Sun Oct 29 01:00:00 GMT-04:00 1967
1447 {0, 0, 0}
1448 };
1449
1450 for (int32_t i=0; DATA[i].id!=0; ++i) {
1451 const char* id = DATA[i].id;
1452 TimeZone *tz = TimeZone::createTimeZone(id);
1453 UnicodeString s;
1454 if (tz == 0) {
1455 errln("FAIL: Cannot create %s", id);
1456 } else if (tz->getID(s) != UnicodeString(id)) {
1457 errln((UnicodeString)"FAIL: createTimeZone(" + id + ") => " + s);
1458 } else {
1459 UErrorCode ec = U_ZERO_ERROR;
1460 int32_t raw, dst;
1461 UDate when = (double) DATA[i].time * U_MILLIS_PER_SECOND;
1462 tz->getOffset(when, FALSE, raw, dst, ec);
1463 if (U_FAILURE(ec)) {
1464 errln("FAIL: getOffset");
1465 } else if ((raw+dst) != DATA[i].offset) {
1466 errln((UnicodeString)"FAIL: " + DATA[i].id + ".getOffset(" +
1467 //when + " = " +
1468 dateToString(when) + ") => " +
1469 raw + ", " + dst);
1470 } else {
1471 logln((UnicodeString)"Ok: " + DATA[i].id + ".getOffset(" +
1472 //when + " = " +
1473 dateToString(when) + ") => " +
1474 raw + ", " + dst);
1475 }
1476 }
1477 delete tz;
1478 }
1479}
1480
1481void TimeZoneTest::TestEquivalentIDs() {
1482 int32_t n = TimeZone::countEquivalentIDs("PST");
1483 if (n < 2) {
1484 errln((UnicodeString)"FAIL: countEquivalentIDs(PST) = " + n);
1485 } else {
1486 UBool sawLA = FALSE;
1487 for (int32_t i=0; i<n; ++i) {
1488 UnicodeString id = TimeZone::getEquivalentID("PST", i);
1489 logln((UnicodeString)"" + i + " : " + id);
1490 if (id == UnicodeString("America/Los_Angeles")) {
1491 sawLA = TRUE;
1492 }
1493 }
1494 if (!sawLA) {
1495 errln("FAIL: America/Los_Angeles should be in the list");
1496 }
1497 }
1498}
1499
b75a7d8f 1500#endif /* #if !UCONFIG_NO_FORMATTING */