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