1 /***********************************************************************
3 * Copyright (c) 1997-2006, International Business Machines Corporation
4 * and others. All Rights Reserved.
5 ***********************************************************************/
7 #include "unicode/utypes.h"
9 #if !UCONFIG_NO_FORMATTING
11 #include "unicode/timezone.h"
12 #include "unicode/simpletz.h"
13 #include "unicode/calendar.h"
14 #include "unicode/gregocal.h"
15 #include "unicode/resbund.h"
16 #include "unicode/strenum.h"
21 #define CASE(id,test) case id: \
24 logln(#test "---"); logln(""); \
29 // *****************************************************************************
31 // *****************************************************************************
33 void TimeZoneTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/ )
35 if (exec
) logln("TestSuite TestTimeZone");
37 CASE(0, TestPRTOffset
);
38 CASE(1, TestVariousAPI518
);
39 CASE(2, TestGetAvailableIDs913
);
40 CASE(3, TestGenericAPI
);
42 CASE(5, TestShortZoneIDs
);
43 CASE(6, TestCustomParse
);
44 CASE(7, TestDisplayName
);
45 CASE(8, TestDSTSavings
);
46 CASE(9, TestAlternateRules
);
47 CASE(10,TestCountries
);
48 CASE(11,TestHistorical
);
49 CASE(12,TestEquivalentIDs
);
50 CASE(13, TestAliasedNames
);
51 CASE(14, TestFractionalDST
);
52 default: name
= ""; break;
56 const int32_t TimeZoneTest::millisPerHour
= 3600000;
58 // ---------------------------------------------------------------------------------
61 * Generic API testing for API coverage.
64 TimeZoneTest::TestGenericAPI()
66 UnicodeString
id("NewGMT");
67 int32_t offset
= 12345;
69 SimpleTimeZone
*zone
= new SimpleTimeZone(offset
, id
);
70 if (zone
->useDaylightTime()) errln("FAIL: useDaylightTime should return FALSE");
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");
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");
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");
88 TimeZone
* saveDefault
= TimeZone::createDefault();
89 logln((UnicodeString
)"TimeZone::createDefault() => " + saveDefault
->getID(id
));
90 //TimeZone* pstZone = TimeZone::createTimeZone("PST");
92 logln("call uprv_timezone() which uses the host");
93 logln("to get the difference in seconds between coordinated universal");
94 logln("time and local time. E.g., -28,800 for PST (GMT-8hrs)");
96 int32_t tzoffset
= uprv_timezone();
97 logln(UnicodeString("Value returned from uprv_timezone = ") + tzoffset
);
98 // Invert sign because UNIX semantics are backwards
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");
107 if (tzoffset
!= 28800) {
108 logln("***** WARNING: If testing in the PST timezone, uprv_timezone should return 28800! *****");
110 if ((tzoffset
% 1800 != 0)) {
111 errln("FAIL: t_timezone may be incorrect. It is not a multiple of 30min. It is %d", tzoffset
);
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
);
125 // ---------------------------------------------------------------------------------
128 * Test the setStartRule/setEndRule API calls.
131 TimeZoneTest::TestRuleAPI()
133 UErrorCode status
= U_ZERO_ERROR
;
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");
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;
144 gc
->set(1990, UCAL_MARCH
, 1);
145 UDate marchOneStd
= gc
->getTime(status
); // Local Std time midnight
147 gc
->set(1990, UCAL_JULY
, 1);
148 UDate julyOneStd
= gc
->getTime(status
); // Local Std time midnight
149 if (failure(status
, "GregorianCalendar::getTime")) return;
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);
155 zone
->setStartRule(UCAL_MARCH
, 1, 0, startHour
, status
);
156 zone
->setEndRule (UCAL_JULY
, 1, 0, endHour
, status
);
159 gc
= new GregorianCalendar(*zone
, status
);
160 if (failure(status
, "new GregorianCalendar")) return;
162 UDate marchOne
= marchOneStd
+ startHour
;
163 UDate julyOne
= julyOneStd
+ endHour
- 3600000; // Adjust from wall to Std time
165 UDate expMarchOne
= 636251400000.0;
166 if (marchOne
!= expMarchOne
)
168 errln((UnicodeString
)"FAIL: Expected start computed as " + marchOne
+
169 " = " + dateToString(marchOne
));
170 logln((UnicodeString
)" Should be " + expMarchOne
+
171 " = " + dateToString(expMarchOne
));
174 UDate expJulyOne
= 646793100000.0;
175 if (julyOne
!= expJulyOne
)
177 errln((UnicodeString
)"FAIL: Expected start computed as " + julyOne
+
178 " = " + dateToString(julyOne
));
179 logln((UnicodeString
)" Should be " + expJulyOne
+
180 " = " + dateToString(expJulyOne
));
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
);
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");
193 zone
->setStartYear(1991);
194 if (zone
->inDaylightTime(marchOne
, status
) ||
195 zone
->inDaylightTime(julyOne
- 1000, status
))
196 errln("FAIL: Start year broken");
198 failure(status
, "TestRuleAPI");
204 TimeZoneTest::findTransition(const TimeZone
& tz
,
205 UDate min
, UDate max
) {
206 UErrorCode ec
= U_ZERO_ERROR
;
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"));
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
) {
223 if (failure(ec
, "TimeZone::inDaylightTime")) return;
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
));
234 TimeZoneTest::testUsingBinarySearch(const TimeZone
& tz
,
235 UDate min
, UDate max
,
236 UDate expectedBoundary
)
238 UErrorCode status
= U_ZERO_ERROR
;
239 UBool startsInDST
= tz
.inDaylightTime(min
, status
);
240 if (failure(status
, "TimeZone::inDaylightTime")) return;
241 if (tz
.inDaylightTime(max
, status
) == startsInDST
) {
242 logln("Error: inDaylightTime(" + dateToString(max
) + ") != " + ((!startsInDST
)?"TRUE":"FALSE"));
245 if (failure(status
, "TimeZone::inDaylightTime")) return;
246 while ((max
- min
) > INTERVAL
) {
247 UDate mid
= (min
+ max
) / 2;
248 if (tz
.inDaylightTime(mid
, status
) == startsInDST
) {
253 if (failure(status
, "TimeZone::inDaylightTime")) return;
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
;
260 mindelta
<= INTERVAL
&&
262 maxdelta
<= INTERVAL
)
263 logln(UnicodeString("PASS: Expected bdry: ") + expectedBoundary
+ " = " + dateToString(expectedBoundary
));
265 errln(UnicodeString("FAIL: Expected bdry: ") + expectedBoundary
+ " = " + dateToString(expectedBoundary
));
268 const UDate
TimeZoneTest::INTERVAL
= 100;
270 // ---------------------------------------------------------------------------------
272 // -------------------------------------
275 * Test the offset of the PRT timezone.
278 TimeZoneTest::TestPRTOffset()
280 TimeZone
* tz
= TimeZone::createTimeZone("PRT");
282 errln("FAIL: TimeZone(PRT) is null");
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
);
292 logln("PASS: Offset for PRT should be %d, found %d", expectedHour
, foundHour
);
298 // -------------------------------------
301 * Regress a specific bug with a sequence of API calls.
304 TimeZoneTest::TestVariousAPI518()
306 UErrorCode status
= U_ZERO_ERROR
;
307 TimeZone
* time_zone
= TimeZone::createTimeZone("PST");
308 UDate d
= date(97, UCAL_APRIL
, 30);
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; }
327 // -------------------------------------
330 * Test the call which retrieves the available IDs.
333 TimeZoneTest::TestGetAvailableIDs913()
335 UErrorCode ec
= U_ZERO_ERROR
;
338 #ifdef U_USE_TIMEZONE_OBSOLETE_2_8
339 // Test legacy API -- remove these tests when the corresponding API goes away (duh)
341 const UnicodeString
** ids
= TimeZone::createAvailableIDs(numIDs
);
342 if (ids
== 0 || numIDs
< 1) {
343 errln("FAIL: createAvailableIDs()");
345 UnicodeString
buf("TimeZone::createAvailableIDs() = { ");
346 for(i
=0; i
<numIDs
; ++i
) {
347 if (i
) buf
.append(", ");
352 // we own the array; the caller owns the contained strings (yuck)
357 ids
= TimeZone::createAvailableIDs(-8*U_MILLIS_PER_HOUR
, numIDs
);
358 if (ids
== 0 || numIDs
< 1) {
359 errln("FAIL: createAvailableIDs(-8:00)");
361 UnicodeString
buf("TimeZone::createAvailableIDs(-8:00) = { ");
362 for(i
=0; i
<numIDs
; ++i
) {
363 if (i
) buf
.append(", ");
368 // we own the array; the caller owns the contained strings (yuck)
372 ids
= TimeZone::createAvailableIDs("US", numIDs
);
373 if (ids
== 0 || numIDs
< 1) {
374 errln("FAIL: createAvailableIDs(US) ids=%d, numIDs=%d", ids
, numIDs
);
376 UnicodeString
buf("TimeZone::createAvailableIDs(US) = { ");
377 for(i
=0; i
<numIDs
; ++i
) {
378 if (i
) buf
.append(", ");
383 // we own the array; the caller owns the contained strings (yuck)
389 UnicodeString
*buf
= new UnicodeString("TimeZone::createEnumeration() = { ");
391 StringEnumeration
* s
= TimeZone::createEnumeration();
392 s_length
= s
->count(ec
);
393 for (i
= 0; i
< s_length
;++i
) {
394 if (i
> 0) *buf
+= ", ";
396 *buf
+= *s
->snext(ec
);
398 *buf
+= UnicodeString(s
->next(NULL
, ec
), "");
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");
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.
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
);
426 errln(UnicodeString("FAIL: createTimeZone(") +
428 } else if (z
->getID(str
) != *id
) {
429 errln(UnicodeString("FAIL: createTimeZone(") +
430 *id
+ ") -> zone " + str
);
432 logln(UnicodeString("OK: createTimeZone(") +
433 *id
+ ") succeeded");
441 *buf
+= "TimeZone::createEnumeration(GMT+01:00) = { ";
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
);
455 *buf
+= "TimeZone::createEnumeration(US) = { ";
457 s
= TimeZone::createEnumeration("US");
458 s_length
= s
->count(ec
);
459 for (i
= 0; i
< s_length
;++i
) {
460 if (i
> 0) *buf
+= ", ";
461 *buf
+= *s
->snext(ec
);
466 TimeZone
*tz
= TimeZone::createTimeZone("PST");
467 if (tz
!= 0) logln("getTimeZone(PST) = " + tz
->getID(str
));
468 else errln("FAIL: getTimeZone(PST) = null");
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");
476 tz
= TimeZone::createTimeZone("NON_EXISTENT");
479 errln("FAIL: getTimeZone(NON_EXISTENT) = null");
480 else if (tz
->getID(temp
) != "GMT")
481 errln("FAIL: getTimeZone(NON_EXISTENT) = " + temp
);
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]
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.
510 * Added tests for additional zones and aliases from the icuzones file.
511 * Markus Scherer 2006-nov-06
513 * [srl - from java - 7/5/1998]
515 * Certain short zone IDs, used since 1.1.x, are incorrect.
517 * The worst of these is:
519 * "CAT" (Central African Time) should be GMT+2:00, but instead returns a
520 * zone at GMT-1:00. The zone at GMT-1:00 should be called EGT, CVT, EGST,
521 * or AZOST, depending on which zone is meant, but in no case is it CAT.
523 * Other wrong zone IDs:
525 * ECT (European Central Time) GMT+1:00: ECT is Ecuador Time,
526 * GMT-5:00. European Central time is abbreviated CEST.
528 * SST (Solomon Island Time) GMT+11:00. SST is actually Samoa Standard Time,
529 * GMT-11:00. Solomon Island time is SBT.
531 * NST (New Zealand Time) GMT+12:00. NST is the abbreviation for
532 * Newfoundland Standard Time, GMT-3:30. New Zealanders use NZST.
534 * AST (Alaska Standard Time) GMT-9:00. [This has already been noted in
535 * another bug.] It should be "AKST". AST is Atlantic Standard Time,
538 * PNT (Phoenix Time) GMT-7:00. PNT usually means Pitcairn Time,
539 * GMT-8:30. There is no standard abbreviation for Phoenix time, as distinct
540 * from MST with daylight savings.
542 * In addition to these problems, a number of zones are FAKE. That is, they
543 * don't match what people use in the real world.
547 * EET (should be EEST)
548 * ART (should be EEST)
549 * MET (should be IRST)
550 * NET (should be AMST)
551 * PLT (should be PKT)
552 * BST (should be BDT)
553 * VST (should be ICT)
554 * CTT (should be CST) +
555 * ACT (should be CST) +
556 * AET (should be EST) +
557 * MIT (should be WST) +
558 * IET (should be EST) +
559 * PRT (should be AST) +
560 * CNT (should be NST)
561 * AGT (should be ARST)
562 * BET (should be EST) +
564 * + A zone with the correct name already exists and means something
565 * else. E.g., EST usually indicates the US Eastern zone, so it cannot be
566 * used for Brazil (BET).
568 void TimeZoneTest::TestShortZoneIDs()
571 // Create a small struct to hold the array
580 {"MIT", -660, FALSE
},
581 {"HST", -600, FALSE
},
584 {"PNT", -420, FALSE
},
585 {"MST", -420, FALSE
}, // updated Aug 2003 aliu
587 {"IET", -300, TRUE
}, // updated Jan 2006 srl
588 {"EST", -300, FALSE
}, // updated Aug 2003 aliu
589 {"PRT", -240, FALSE
},
591 {"AGT", -180, TRUE
}, // updated by tzdata2007k
593 // "CAT", -60, FALSE, // Wrong:
594 // As of bug 4130885, fix CAT (Central Africa)
595 {"CAT", 120, FALSE
}, // Africa/Harare
597 {"UTC", 0, FALSE
}, // ** srl: seems broken in C++
602 {"MET", 60, TRUE
}, // updated 12/3/99 aliu
603 {"NET", 240, TRUE
}, // updated 12/3/99 aliu
604 {"PLT", 300, TRUE
}, // updated by 2008c
608 {"CTT", 480, FALSE
}, // updated Aug 2003 aliu
610 {"ACT", 570, FALSE
}, // updated Aug 2003 aliu
613 // "NST", 720, FALSE,
614 // As of bug 4130885, fix NST (New Zealand)
615 {"NST", 720, TRUE
}, // Pacific/Auckland
620 for(i
=0;kReferenceList
[i
].id
[0];i
++) {
621 UnicodeString
itsID(kReferenceList
[i
].id
);
624 TimeZone
*tz
= TimeZone::createTimeZone(itsID
);
626 errln("FAIL: Time Zone " + itsID
+ " does not exist!");
630 // Check daylight usage.
631 UBool usesDaylight
= tz
->useDaylightTime();
632 if (usesDaylight
!= kReferenceList
[i
].daylight
) {
633 errln("FAIL: Time Zone " + itsID
+ " use daylight is " +
634 (usesDaylight
?"TRUE":"FALSE") +
635 " but it should be " +
636 ((kReferenceList
[i
].daylight
)?"TRUE":"FALSE"));
641 int32_t offsetInMinutes
= tz
->getRawOffset()/60000;
642 if (offsetInMinutes
!= kReferenceList
[i
].offset
) {
643 errln("FAIL: Time Zone " + itsID
+ " raw offset is " +
645 " but it should be " + kReferenceList
[i
].offset
);
650 logln("OK: " + itsID
+
651 " useDaylightTime() & getRawOffset() as expected");
657 // OK now test compat
658 logln("Testing for compatibility zones");
660 const char* compatibilityMap
[] = {
661 // This list is copied from tz.alias. If tz.alias
662 // changes, this list must be updated. Current as of Mar 2007
663 "ACT", "Australia/Darwin",
664 "AET", "Australia/Sydney",
665 "AGT", "America/Buenos_Aires",
666 "ART", "Africa/Cairo",
667 "AST", "America/Anchorage",
668 "BET", "America/Sao_Paulo",
669 "BST", "Asia/Dhaka", // # spelling changed in 2000h; was Asia/Dacca
670 "CAT", "Africa/Harare",
671 "CNT", "America/St_Johns",
672 "CST", "America/Chicago",
673 "CTT", "Asia/Shanghai",
674 "EAT", "Africa/Addis_Ababa",
675 "ECT", "Europe/Paris",
676 // EET Europe/Istanbul # EET is a standard UNIX zone
677 // "EST", "America/New_York", # Defined as -05:00
678 // "HST", "Pacific/Honolulu", # Defined as -10:00
679 "IET", "America/Indianapolis",
680 "IST", "Asia/Calcutta",
682 // MET Asia/Tehran # MET is a standard UNIX zone
683 "MIT", "Pacific/Apia",
684 // "MST", "America/Denver", # Defined as -07:00
685 "NET", "Asia/Yerevan",
686 "NST", "Pacific/Auckland",
687 "PLT", "Asia/Karachi",
688 "PNT", "America/Phoenix",
689 "PRT", "America/Puerto_Rico",
690 "PST", "America/Los_Angeles",
691 "SST", "Pacific/Guadalcanal",
693 "VST", "Asia/Saigon",
697 for (i
=0;*compatibilityMap
[i
];i
+=2) {
700 const char *zone1
= compatibilityMap
[i
];
701 const char *zone2
= compatibilityMap
[i
+1];
703 TimeZone
*tz1
= TimeZone::createTimeZone(zone1
);
704 TimeZone
*tz2
= TimeZone::createTimeZone(zone2
);
707 errln(UnicodeString("FAIL: Could not find short ID zone ") + zone1
);
710 errln(UnicodeString("FAIL: Could not find long ID zone ") + zone2
);
714 // make NAME same so comparison will only look at the rest
715 tz2
->setID(tz1
->getID(itsID
));
718 errln("FAIL: " + UnicodeString(zone1
) +
719 " != " + UnicodeString(zone2
));
721 logln("OK: " + UnicodeString(zone1
) +
722 " == " + UnicodeString(zone2
));
732 * Utility function for TestCustomParse
734 UnicodeString
& TimeZoneTest::formatMinutes(int32_t min
, UnicodeString
& rv
)
739 if (min
< 0) { sign
= '-'; min
= -min
; }
745 rv
+= UChar(0x0030 + (h
/10));
746 rv
+= UChar(0x0030 + (h%10
));
751 rv
+= UChar(0x0030 + (min
/10));
755 rv
+= UChar(0x0030 + (min%10
));
762 * As part of the VM fix (see CCC approved RFE 4028006, bug
763 * 4044013), TimeZone.getTimeZone() has been modified to recognize
764 * generic IDs of the form GMT[+-]hh:mm, GMT[+-]hhmm, and
765 * GMT[+-]hh. Test this behavior here.
769 void TimeZoneTest::TestCustomParse()
772 const int32_t kUnparseable
= 604800; // the number of seconds in a week. More than any offset should be.
773 const UnicodeString kExpectedCustomID
= "Custom";
777 const char *customId
;
778 int32_t expectedOffset
;
782 // ID Expected offset in minutes
783 //{"GMT", kUnparseable}, //Isn't custom. Can't test it here. [returns normal GMT]
784 {"GMT-YOUR.AD.HERE", kUnparseable
},
785 // {"GMT0", kUnparseable}, // ICU 2.8: An Olson zone ID
786 // {"GMT+0", (0)}, // ICU 2.8: An Olson zone ID
789 {"GMT+15:99", (15*60+99)},
790 {"GMT+", kUnparseable
},
791 {"GMT-", kUnparseable
},
792 {"GMT+0:", kUnparseable
},
793 {"GMT-:", kUnparseable
},
794 {"GMT-YOUR.AD.HERE", kUnparseable
},
795 {"GMT+0010", (10)}, // Interpret this as 00:10
796 {"GMT-10", (-10*60)},
798 {"GMT-3:30", (-(3*60+30))},
799 {"GMT-230", (-(2*60+30))},
803 for (i
=0; kData
[i
].customId
!= 0; i
++)
805 UnicodeString
id(kData
[i
].customId
);
806 int32_t exp
= kData
[i
].expectedOffset
;
808 { // for no data test Jitterbug 4354
809 UErrorCode success = U_ZERO_ERROR;
810 NumberFormat* numberFormat = NumberFormat::createInstance(success);
811 if (U_FAILURE(success)) {
812 dataerrln(" NumberFormat::createInstance() error");
819 TimeZone
*zone
= TimeZone::createTimeZone(id
);
820 UnicodeString itsID
, temp
;
823 logln("testing # " + formatMinutes(i
, temp
) + id
);
828 errln("FAIL: Could not createTimeZone(" + id + "). Returned NULL.");
834 if (! zone
->getID(itsID
).compare("GMT"))
837 logln(id
+ " -> generic GMT");
838 // When TimeZone.getTimeZone() can't parse the id, it
839 // returns GMT -- a dubious practice, but required for
840 // backward compatibility.
841 if (exp
!= kUnparseable
) {
842 errln("FAIL: Expected offset of " + formatMinutes(exp
,temp
) +
843 " for " + id
+ ", got parse failure");
849 int32_t ioffset
= zone
->getRawOffset()/60000;
850 UnicodeString offset
;
851 formatMinutes(ioffset
, offset
);
852 logln(id
+ " -> " + itsID
+ " GMT" + offset
);
853 if (exp
== kUnparseable
)
855 errln("FAIL: Expected parse failure for " + id
+
856 ", got offset of " + offset
+
859 else if (ioffset
!= exp
||
860 (itsID
.compare(kExpectedCustomID
) != 0))
862 errln("Expected offset of " + formatMinutes(exp
,temp
) +
863 ", id Custom, for " + id
+
864 ", got offset of " + offset
+
872 static const UVersionInfo ICU_37
= {3,7,0,0};
875 TimeZoneTest::TestAliasedNames()
881 /* Generated by org.unicode.cldr.tool.CountItems */
883 /* zoneID, canonical zoneID */
884 {"Africa/Timbuktu", "Africa/Bamako"},
885 {"America/Argentina/Buenos_Aires", "America/Buenos_Aires"},
886 {"America/Argentina/Catamarca", "America/Catamarca"},
887 {"America/Argentina/ComodRivadavia", "America/Catamarca"},
888 {"America/Argentina/Cordoba", "America/Cordoba"},
889 {"America/Argentina/Jujuy", "America/Jujuy"},
890 {"America/Argentina/Mendoza", "America/Mendoza"},
891 {"America/Atka", "America/Adak"},
892 {"America/Ensenada", "America/Tijuana"},
893 {"America/Fort_Wayne", "America/Indiana/Indianapolis"},
894 {"America/Indianapolis", "America/Indiana/Indianapolis"},
895 {"America/Knox_IN", "America/Indiana/Knox"},
896 {"America/Louisville", "America/Kentucky/Louisville"},
897 {"America/Porto_Acre", "America/Rio_Branco"},
898 {"America/Rosario", "America/Cordoba"},
899 {"America/Virgin", "America/St_Thomas"},
900 {"Asia/Ashkhabad", "Asia/Ashgabat"},
901 {"Asia/Chungking", "Asia/Chongqing"},
902 {"Asia/Dacca", "Asia/Dhaka"},
903 {"Asia/Istanbul", "Europe/Istanbul"},
904 {"Asia/Macao", "Asia/Macau"},
905 {"Asia/Tel_Aviv", "Asia/Jerusalem"},
906 {"Asia/Thimbu", "Asia/Thimphu"},
907 {"Asia/Ujung_Pandang", "Asia/Makassar"},
908 {"Asia/Ulan_Bator", "Asia/Ulaanbaatar"},
909 {"Australia/ACT", "Australia/Sydney"},
910 {"Australia/Canberra", "Australia/Sydney"},
911 {"Australia/LHI", "Australia/Lord_Howe"},
912 {"Australia/NSW", "Australia/Sydney"},
913 {"Australia/North", "Australia/Darwin"},
914 {"Australia/Queensland", "Australia/Brisbane"},
915 {"Australia/South", "Australia/Adelaide"},
916 {"Australia/Tasmania", "Australia/Hobart"},
917 {"Australia/Victoria", "Australia/Melbourne"},
918 {"Australia/West", "Australia/Perth"},
919 {"Australia/Yancowinna", "Australia/Broken_Hill"},
920 {"Brazil/Acre", "America/Rio_Branco"},
921 {"Brazil/DeNoronha", "America/Noronha"},
922 {"Brazil/East", "America/Sao_Paulo"},
923 {"Brazil/West", "America/Manaus"},
924 {"Canada/Atlantic", "America/Halifax"},
925 {"Canada/Central", "America/Winnipeg"},
926 {"Canada/East-Saskatchewan", "America/Regina"},
927 {"Canada/Eastern", "America/Toronto"},
928 {"Canada/Mountain", "America/Edmonton"},
929 {"Canada/Newfoundland", "America/St_Johns"},
930 {"Canada/Pacific", "America/Vancouver"},
931 {"Canada/Saskatchewan", "America/Regina"},
932 {"Canada/Yukon", "America/Whitehorse"},
933 {"Chile/Continental", "America/Santiago"},
934 {"Chile/EasterIsland", "Pacific/Easter"},
935 {"Cuba", "America/Havana"},
936 {"Egypt", "Africa/Cairo"},
937 {"Eire", "Europe/Dublin"},
938 {"Etc/GMT+0", "Etc/GMT"},
939 {"Etc/GMT-0", "Etc/GMT"},
940 {"Etc/GMT0", "Etc/GMT"},
941 {"Etc/Greenwich", "Etc/GMT"},
942 {"Etc/UCT", "Etc/GMT"},
943 {"Etc/UTC", "Etc/GMT"},
944 {"Etc/Universal", "Etc/GMT"},
945 {"Etc/Zulu", "Etc/GMT"},
946 {"Europe/Belfast", "Europe/London"},
947 {"Europe/Nicosia", "Asia/Nicosia"},
948 {"Europe/Tiraspol", "Europe/Chisinau"},
949 {"GB", "Europe/London"},
950 {"GB-Eire", "Europe/London"},
952 {"GMT+0", "Etc/GMT"},
953 {"GMT-0", "Etc/GMT"},
955 {"Greenwich", "Etc/GMT"},
956 {"Hongkong", "Asia/Hong_Kong"},
957 {"Iceland", "Atlantic/Reykjavik"},
958 {"Iran", "Asia/Tehran"},
959 {"Israel", "Asia/Jerusalem"},
960 {"Jamaica", "America/Jamaica"},
961 {"Japan", "Asia/Tokyo"},
962 {"Kwajalein", "Pacific/Kwajalein"},
963 {"Libya", "Africa/Tripoli"},
964 {"Mexico/BajaNorte", "America/Tijuana"},
965 {"Mexico/BajaSur", "America/Mazatlan"},
966 {"Mexico/General", "America/Mexico_City"},
967 {"NZ", "Pacific/Auckland"},
968 {"NZ-CHAT", "Pacific/Chatham"},
969 {"Navajo", "America/Shiprock"},
970 {"PRC", "Asia/Shanghai"},
971 {"Pacific/Samoa", "Pacific/Pago_Pago"},
972 {"Pacific/Yap", "Pacific/Truk"},
973 {"Poland", "Europe/Warsaw"},
974 {"Portugal", "Europe/Lisbon"},
975 {"ROC", "Asia/Taipei"},
976 {"ROK", "Asia/Seoul"},
977 {"Singapore", "Asia/Singapore"},
978 {"Turkey", "Europe/Istanbul"},
980 {"US/Alaska", "America/Anchorage"},
981 {"US/Aleutian", "America/Adak"},
982 {"US/Arizona", "America/Phoenix"},
983 {"US/Central", "America/Chicago"},
984 {"US/East-Indiana", "America/Indiana/Indianapolis"},
985 {"US/Eastern", "America/New_York"},
986 {"US/Hawaii", "Pacific/Honolulu"},
987 {"US/Indiana-Starke", "America/Indiana/Knox"},
988 {"US/Michigan", "America/Detroit"},
989 {"US/Mountain", "America/Denver"},
990 {"US/Pacific", "America/Los_Angeles"},
991 {"US/Pacific-New", "America/Los_Angeles"},
992 {"US/Samoa", "Pacific/Pago_Pago"},
994 {"Universal", "Etc/GMT"},
995 {"W-SU", "Europe/Moscow"},
1001 TimeZone::EDisplayType styles
[] = { TimeZone::SHORT
, TimeZone::LONG
};
1002 UBool useDst
[] = { FALSE
, TRUE
};
1003 int32_t noLoc
= uloc_countAvailable();
1005 if(isICUVersionAtLeast(ICU_37
)) {
1006 errln("This test needs to be fixed. This test fails in exhaustive mode because we need to implement generic timezones.\n");
1009 int32_t i
, j
, k
, loc
;
1010 UnicodeString fromName
, toName
;
1011 TimeZone
*from
= NULL
, *to
= NULL
;
1012 for(i
= 0; i
< (int32_t)(sizeof(kData
)/sizeof(kData
[0])); i
++) {
1013 from
= TimeZone::createTimeZone(kData
[i
].from
);
1014 to
= TimeZone::createTimeZone(kData
[i
].to
);
1015 if(!from
->hasSameRules(*to
)) {
1016 errln("different at %i\n", i
);
1018 if(!quick
&& isICUVersionAtLeast(ICU_37
)) {
1019 errln("This test needs to be fixed. This test fails in exhaustive mode because we need to implement generic timezones.\n");
1020 for(loc
= 0; loc
< noLoc
; loc
++) {
1021 const char* locale
= uloc_getAvailable(loc
);
1022 for(j
= 0; j
< (int32_t)(sizeof(styles
)/sizeof(styles
[0])); j
++) {
1023 for(k
= 0; k
< (int32_t)(sizeof(useDst
)/sizeof(useDst
[0])); k
++) {
1026 from
->getDisplayName(useDst
[k
], styles
[j
],locale
, fromName
);
1027 to
->getDisplayName(useDst
[k
], styles
[j
], locale
, toName
);
1028 if(fromName
.compare(toName
) != 0) {
1029 errln("Fail: Expected "+toName
+" but got " + prettify(fromName
)
1030 + " for locale: " + locale
+ " index: "+ loc
1031 + " to id "+ kData
[i
].to
1032 + " from id " + kData
[i
].from
);
1040 from
->getDisplayName(fromName
);
1041 to
->getDisplayName(toName
);
1042 if(fromName
.compare(toName
) != 0) {
1043 errln("Fail: Expected "+toName
+" but got " + fromName
);
1052 * Test the basic functionality of the getDisplayName() API.
1057 * See also API change request A41.
1059 * 4/21/98 - make smarter, so the test works if the ext resources
1060 * are present or not.
1063 TimeZoneTest::TestDisplayName()
1065 UErrorCode status
= U_ZERO_ERROR
;
1067 TimeZone
*zone
= TimeZone::createTimeZone("PST");
1069 zone
->getDisplayName(Locale::getEnglish(), name
);
1070 logln("PST->" + name
);
1071 if (name
.compare("Pacific Standard Time") != 0)
1072 errln("Fail: Expected \"Pacific Standard Time\" but got " + name
);
1074 //*****************************************************************
1075 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
1076 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
1077 // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
1078 //*****************************************************************
1082 TimeZone::EDisplayType style
;
1085 {FALSE
, TimeZone::SHORT
, "PST"},
1086 {TRUE
, TimeZone::SHORT
, "PDT"},
1087 {FALSE
, TimeZone::LONG
, "Pacific Standard Time"},
1088 {TRUE
, TimeZone::LONG
, "Pacific Daylight Time"},
1090 {FALSE
, TimeZone::LONG
, ""}
1093 for (i
=0; kData
[i
].expect
[0] != '\0'; i
++)
1096 name
= zone
->getDisplayName(kData
[i
].useDst
,
1098 Locale::getEnglish(), name
);
1099 if (name
.compare(kData
[i
].expect
) != 0)
1100 errln("Fail: Expected " + UnicodeString(kData
[i
].expect
) + "; got " + name
);
1101 logln("PST [with options]->" + name
);
1103 for (i
=0; kData
[i
].expect
[0] != '\0'; i
++)
1106 name
= zone
->getDisplayName(kData
[i
].useDst
,
1107 kData
[i
].style
, name
);
1108 if (name
.compare(kData
[i
].expect
) != 0)
1109 errln("Fail: Expected " + UnicodeString(kData
[i
].expect
) + "; got " + name
);
1110 logln("PST [with options]->" + name
);
1114 // Make sure that we don't display the DST name by constructing a fake
1115 // PST zone that has DST all year long.
1116 SimpleTimeZone
*zone2
= new SimpleTimeZone(0, "PST");
1118 zone2
->setStartRule(UCAL_JANUARY
, 1, 0, 0, status
);
1119 zone2
->setEndRule(UCAL_DECEMBER
, 31, 0, 0, status
);
1121 UnicodeString inDaylight
;
1122 if (zone2
->inDaylightTime(UDate(0), status
)) {
1123 inDaylight
= UnicodeString("TRUE");
1125 inDaylight
= UnicodeString("FALSE");
1127 logln(UnicodeString("Modified PST inDaylightTime->") + inDaylight
);
1128 if(U_FAILURE(status
))
1130 errln("Some sort of error..." + UnicodeString(u_errorName(status
))); // REVISIT
1133 name
= zone2
->getDisplayName(Locale::getEnglish(),name
);
1134 logln("Modified PST->" + name
);
1135 if (name
.compare("Pacific Standard Time") != 0)
1136 errln("Fail: Expected \"Pacific Standard Time\"");
1138 // Make sure we get the default display format for Locales
1139 // with no display name data.
1140 Locale
mt_MT("mt_MT");
1142 name
= zone
->getDisplayName(mt_MT
,name
);
1143 //*****************************************************************
1144 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
1145 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
1146 // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
1147 //*****************************************************************
1148 logln("PST(mt_MT)->" + name
);
1150 // *** REVISIT SRL how in the world do I check this? looks java specific.
1151 // Now be smart -- check to see if zh resource is even present.
1152 // If not, we expect the en fallback behavior.
1153 ResourceBundle
enRB(NULL
,
1154 Locale::getEnglish(), status
);
1155 if(U_FAILURE(status
))
1156 errln("Couldn't get ResourceBundle for en");
1158 ResourceBundle
mtRB(NULL
,
1160 //if(U_FAILURE(status))
1161 // errln("Couldn't get ResourceBundle for mt_MT");
1163 UBool noZH
= U_FAILURE(status
);
1166 logln("Warning: Not testing the mt_MT behavior because resource is absent");
1167 if (name
!= "Pacific Standard Time")
1168 errln("Fail: Expected Pacific Standard Time");
1172 if (name
.compare("GMT-08:00") &&
1173 name
.compare("GMT-8:00") &&
1174 name
.compare("GMT-0800") &&
1175 name
.compare("GMT-800")) {
1176 errln(UnicodeString("Fail: Expected GMT-08:00 or something similar for PST in mt_MT but got ") + name
);
1177 errln("************************************************************");
1178 errln("THE ABOVE FAILURE MAY JUST MEAN THE LOCALE DATA HAS CHANGED");
1179 errln("************************************************************");
1182 // Now try a non-existent zone
1184 zone2
= new SimpleTimeZone(90*60*1000, "xyzzy");
1186 name
= zone2
->getDisplayName(Locale::getEnglish(),name
);
1187 logln("GMT+90min->" + name
);
1188 if (name
.compare("GMT+01:30") &&
1189 name
.compare("GMT+1:30") &&
1190 name
.compare("GMT+0130") &&
1191 name
.compare("GMT+130"))
1192 errln("Fail: Expected GMT+01:30 or something similar");
1194 zone2
->getDisplayName(name
);
1195 logln("GMT+90min->" + name
);
1196 if (name
.compare("GMT+01:30") &&
1197 name
.compare("GMT+1:30") &&
1198 name
.compare("GMT+0130") &&
1199 name
.compare("GMT+130"))
1200 errln("Fail: Expected GMT+01:30 or something similar");
1210 TimeZoneTest::TestDSTSavings()
1212 UErrorCode status
= U_ZERO_ERROR
;
1213 // It might be better to find a way to integrate this test into the main TimeZone
1214 // tests above, but I don't have time to figure out how to do this (or if it's
1215 // even really a good idea). Let's consider that a future. --rtg 1/27/98
1216 SimpleTimeZone
*tz
= new SimpleTimeZone(-5 * U_MILLIS_PER_HOUR
, "dstSavingsTest",
1217 UCAL_MARCH
, 1, 0, 0, UCAL_SEPTEMBER
, 1, 0, 0,
1218 (int32_t)(0.5 * U_MILLIS_PER_HOUR
), status
);
1219 if(U_FAILURE(status
))
1220 errln("couldn't create TimeZone");
1222 if (tz
->getRawOffset() != -5 * U_MILLIS_PER_HOUR
)
1223 errln(UnicodeString("Got back a raw offset of ") + (tz
->getRawOffset() / U_MILLIS_PER_HOUR
) +
1224 " hours instead of -5 hours.");
1225 if (!tz
->useDaylightTime())
1226 errln("Test time zone should use DST but claims it doesn't.");
1227 if (tz
->getDSTSavings() != 0.5 * U_MILLIS_PER_HOUR
)
1228 errln(UnicodeString("Set DST offset to 0.5 hour, but got back ") + (tz
->getDSTSavings() /
1229 U_MILLIS_PER_HOUR
) + " hours instead.");
1231 int32_t offset
= tz
->getOffset(GregorianCalendar::AD
, 1998, UCAL_JANUARY
, 1,
1232 UCAL_THURSDAY
, 10 * U_MILLIS_PER_HOUR
,status
);
1233 if (offset
!= -5 * U_MILLIS_PER_HOUR
)
1234 errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ")
1235 + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1237 offset
= tz
->getOffset(GregorianCalendar::AD
, 1998, UCAL_JUNE
, 1, UCAL_MONDAY
,
1238 10 * U_MILLIS_PER_HOUR
,status
);
1239 if (offset
!= -4.5 * U_MILLIS_PER_HOUR
)
1240 errln(UnicodeString("The offset for 10 AM, 6/1/98 should have been -4.5 hours, but we got ")
1241 + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1243 tz
->setDSTSavings(U_MILLIS_PER_HOUR
, status
);
1244 offset
= tz
->getOffset(GregorianCalendar::AD
, 1998, UCAL_JANUARY
, 1,
1245 UCAL_THURSDAY
, 10 * U_MILLIS_PER_HOUR
,status
);
1246 if (offset
!= -5 * U_MILLIS_PER_HOUR
)
1247 errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ")
1248 + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1250 offset
= tz
->getOffset(GregorianCalendar::AD
, 1998, UCAL_JUNE
, 1, UCAL_MONDAY
,
1251 10 * U_MILLIS_PER_HOUR
,status
);
1252 if (offset
!= -4 * U_MILLIS_PER_HOUR
)
1253 errln(UnicodeString("The offset for 10 AM, 6/1/98 (with a 1-hour DST offset) should have been -4 hours, but we got ")
1254 + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1263 TimeZoneTest::TestAlternateRules()
1265 // Like TestDSTSavings, this test should probably be integrated somehow with the main
1266 // test at the top of this class, but I didn't have time to figure out how to do that.
1269 SimpleTimeZone
tz(-5 * U_MILLIS_PER_HOUR
, "alternateRuleTest");
1271 // test the day-of-month API
1272 UErrorCode status
= U_ZERO_ERROR
;
1273 tz
.setStartRule(UCAL_MARCH
, 10, 12 * U_MILLIS_PER_HOUR
, status
);
1274 if(U_FAILURE(status
))
1275 errln("tz.setStartRule failed");
1276 tz
.setEndRule(UCAL_OCTOBER
, 20, 12 * U_MILLIS_PER_HOUR
, status
);
1277 if(U_FAILURE(status
))
1278 errln("tz.setStartRule failed");
1280 int32_t offset
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_MARCH
, 5,
1281 UCAL_THURSDAY
, 10 * U_MILLIS_PER_HOUR
,status
);
1282 if (offset
!= -5 * U_MILLIS_PER_HOUR
)
1283 errln(UnicodeString("The offset for 10AM, 3/5/98 should have been -5 hours, but we got ")
1284 + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1286 offset
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_MARCH
, 15,
1287 UCAL_SUNDAY
, 10 * millisPerHour
,status
);
1288 if (offset
!= -4 * U_MILLIS_PER_HOUR
)
1289 errln(UnicodeString("The offset for 10AM, 3/15/98 should have been -4 hours, but we got ")
1290 + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1292 offset
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_OCTOBER
, 15,
1293 UCAL_THURSDAY
, 10 * millisPerHour
,status
);
1294 if (offset
!= -4 * U_MILLIS_PER_HOUR
)
1295 errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ") + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1297 offset
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_OCTOBER
, 25,
1298 UCAL_SUNDAY
, 10 * millisPerHour
,status
);
1299 if (offset
!= -5 * U_MILLIS_PER_HOUR
)
1300 errln(UnicodeString("The offset for 10AM, 10/25/98 should have been -5 hours, but we got ")
1301 + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1303 // test the day-of-week-after-day-in-month API
1304 tz
.setStartRule(UCAL_MARCH
, 10, UCAL_FRIDAY
, 12 * millisPerHour
, TRUE
, status
);
1305 if(U_FAILURE(status
))
1306 errln("tz.setStartRule failed");
1307 tz
.setEndRule(UCAL_OCTOBER
, 20, UCAL_FRIDAY
, 12 * millisPerHour
, FALSE
, status
);
1308 if(U_FAILURE(status
))
1309 errln("tz.setStartRule failed");
1311 offset
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_MARCH
, 11,
1312 UCAL_WEDNESDAY
, 10 * millisPerHour
,status
);
1313 if (offset
!= -5 * U_MILLIS_PER_HOUR
)
1314 errln(UnicodeString("The offset for 10AM, 3/11/98 should have been -5 hours, but we got ")
1315 + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1317 offset
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_MARCH
, 14,
1318 UCAL_SATURDAY
, 10 * millisPerHour
,status
);
1319 if (offset
!= -4 * U_MILLIS_PER_HOUR
)
1320 errln(UnicodeString("The offset for 10AM, 3/14/98 should have been -4 hours, but we got ")
1321 + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1323 offset
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_OCTOBER
, 15,
1324 UCAL_THURSDAY
, 10 * millisPerHour
,status
);
1325 if (offset
!= -4 * U_MILLIS_PER_HOUR
)
1326 errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ")
1327 + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1329 offset
= tz
.getOffset(GregorianCalendar::AD
, 1998, UCAL_OCTOBER
, 17,
1330 UCAL_SATURDAY
, 10 * millisPerHour
,status
);
1331 if (offset
!= -5 * U_MILLIS_PER_HOUR
)
1332 errln(UnicodeString("The offset for 10AM, 10/17/98 should have been -5 hours, but we got ")
1333 + (offset
/ U_MILLIS_PER_HOUR
) + " hours.");
1336 void TimeZoneTest::TestFractionalDST() {
1337 const char* tzName
= "Australia/Lord_Howe"; // 30 min offset
1338 TimeZone
* tz_icu
= TimeZone::createTimeZone(tzName
);
1339 int dst_icu
= tz_icu
->getDSTSavings();
1341 int32_t expected
= 1800000;
1342 if (expected
!= dst_icu
) {
1343 errln(UnicodeString("java reports dst savings of ") + expected
+
1344 " but icu reports " + dst_icu
+
1345 " for tz " + tz_icu
->getID(id
));
1347 logln(UnicodeString("both java and icu report dst savings of ") + expected
+ " for tz " + tz_icu
->getID(id
));
1353 * Test country code support. Jitterbug 776.
1355 void TimeZoneTest::TestCountries() {
1356 // Make sure America/Los_Angeles is in the "US" group, and
1357 // Asia/Tokyo isn't. Vice versa for the "JP" group.
1358 UErrorCode ec
= U_ZERO_ERROR
;
1360 StringEnumeration
* s
= TimeZone::createEnumeration("US");
1362 UBool la
= FALSE
, tokyo
= FALSE
;
1363 UnicodeString
laZone("America/Los_Angeles", "");
1364 UnicodeString
tokyoZone("Asia/Tokyo", "");
1367 if (s
== NULL
|| n
<= 0) {
1368 errln("FAIL: TimeZone::createEnumeration() returned nothing");
1371 for (i
=0; i
<n
; ++i
) {
1372 const UnicodeString
* id
= s
->snext(ec
);
1373 if (*id
== (laZone
)) {
1376 if (*id
== (tokyoZone
)) {
1381 errln("FAIL: " + laZone
+ " in US = " + la
);
1382 errln("FAIL: " + tokyoZone
+ " in US = " + tokyo
);
1386 s
= TimeZone::createEnumeration("JP");
1388 la
= FALSE
; tokyo
= FALSE
;
1390 for (i
=0; i
<n
; ++i
) {
1391 const UnicodeString
* id
= s
->snext(ec
);
1392 if (*id
== (laZone
)) {
1395 if (*id
== (tokyoZone
)) {
1400 errln("FAIL: " + laZone
+ " in JP = " + la
);
1401 errln("FAIL: " + tokyoZone
+ " in JP = " + tokyo
);
1403 StringEnumeration
* s1
= TimeZone::createEnumeration("US");
1404 StringEnumeration
* s2
= TimeZone::createEnumeration("US");
1406 const UnicodeString
* id1
= s1
->snext(ec
);
1407 if(id1
==NULL
|| U_FAILURE(ec
)){
1408 errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n
,i
);
1410 TimeZone
* tz1
= TimeZone::createTimeZone(*id1
);
1411 for(int j
=0; j
<n
;++j
){
1412 const UnicodeString
* id2
= s2
->snext(ec
);
1413 if(id2
==NULL
|| U_FAILURE(ec
)){
1414 errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n
,i
);
1416 TimeZone
* tz2
= TimeZone::createTimeZone(*id2
);
1417 if(tz1
->hasSameRules(*tz2
)){
1418 logln("ID1 : " + *id1
+" == ID2 : " +*id2
);
1429 void TimeZoneTest::TestHistorical() {
1430 const int32_t H
= U_MILLIS_PER_HOUR
;
1433 int32_t time
; // epoch seconds
1434 int32_t offset
; // total offset (millis)
1436 // Add transition points (before/after) as desired to test historical
1438 {"America/Los_Angeles", 638963999, -8*H
}, // Sun Apr 01 01:59:59 GMT-08:00 1990
1439 {"America/Los_Angeles", 638964000, -7*H
}, // Sun Apr 01 03:00:00 GMT-07:00 1990
1440 {"America/Los_Angeles", 657104399, -7*H
}, // Sun Oct 28 01:59:59 GMT-07:00 1990
1441 {"America/Los_Angeles", 657104400, -8*H
}, // Sun Oct 28 01:00:00 GMT-08:00 1990
1442 {"America/Goose_Bay", -116445601, -4*H
}, // Sun Apr 24 01:59:59 GMT-04:00 1966
1443 {"America/Goose_Bay", -116445600, -3*H
}, // Sun Apr 24 03:00:00 GMT-03:00 1966
1444 {"America/Goose_Bay", -100119601, -3*H
}, // Sun Oct 30 01:59:59 GMT-03:00 1966
1445 {"America/Goose_Bay", -100119600, -4*H
}, // Sun Oct 30 01:00:00 GMT-04:00 1966
1446 {"America/Goose_Bay", -84391201, -4*H
}, // Sun Apr 30 01:59:59 GMT-04:00 1967
1447 {"America/Goose_Bay", -84391200, -3*H
}, // Sun Apr 30 03:00:00 GMT-03:00 1967
1448 {"America/Goose_Bay", -68670001, -3*H
}, // Sun Oct 29 01:59:59 GMT-03:00 1967
1449 {"America/Goose_Bay", -68670000, -4*H
}, // Sun Oct 29 01:00:00 GMT-04:00 1967
1453 for (int32_t i
=0; DATA
[i
].id
!=0; ++i
) {
1454 const char* id
= DATA
[i
].id
;
1455 TimeZone
*tz
= TimeZone::createTimeZone(id
);
1458 errln("FAIL: Cannot create %s", id
);
1459 } else if (tz
->getID(s
) != UnicodeString(id
)) {
1460 errln((UnicodeString
)"FAIL: createTimeZone(" + id
+ ") => " + s
);
1462 UErrorCode ec
= U_ZERO_ERROR
;
1464 UDate when
= (double) DATA
[i
].time
* U_MILLIS_PER_SECOND
;
1465 tz
->getOffset(when
, FALSE
, raw
, dst
, ec
);
1466 if (U_FAILURE(ec
)) {
1467 errln("FAIL: getOffset");
1468 } else if ((raw
+dst
) != DATA
[i
].offset
) {
1469 errln((UnicodeString
)"FAIL: " + DATA
[i
].id
+ ".getOffset(" +
1471 dateToString(when
) + ") => " +
1474 logln((UnicodeString
)"Ok: " + DATA
[i
].id
+ ".getOffset(" +
1476 dateToString(when
) + ") => " +
1484 void TimeZoneTest::TestEquivalentIDs() {
1485 int32_t n
= TimeZone::countEquivalentIDs("PST");
1487 errln((UnicodeString
)"FAIL: countEquivalentIDs(PST) = " + n
);
1489 UBool sawLA
= FALSE
;
1490 for (int32_t i
=0; i
<n
; ++i
) {
1491 UnicodeString id
= TimeZone::getEquivalentID("PST", i
);
1492 logln((UnicodeString
)"" + i
+ " : " + id
);
1493 if (id
== UnicodeString("America/Los_Angeles")) {
1498 errln("FAIL: America/Los_Angeles should be in the list");
1503 #endif /* #if !UCONFIG_NO_FORMATTING */