1 /*
2 *******************************************************************************
3 * Copyright (C) 2007, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
6 */
7
8 #include "unicode/utypes.h"
9
10 #if !UCONFIG_NO_FORMATTING
11
12 #include "unicode/dtrule.h"
13 #include "unicode/tzrule.h"
14 #include "unicode/rbtz.h"
15 #include "unicode/simpletz.h"
16 #include "unicode/tzrule.h"
17 #include "unicode/calendar.h"
18 #include "unicode/gregocal.h"
19 #include "unicode/ucal.h"
20 #include "unicode/unistr.h"
21 #include "unicode/tztrans.h"
22 #include "unicode/vtzone.h"
23 #include "tzrulets.h"
24
25 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
26 #define HOUR (60*60*1000)
27
28 static const char *const TESTZIDS[] = {
29 "AGT",
30 "America/New_York",
31 "America/Los_Angeles",
32 "America/Indiana/Indianapolis",
33 "America/Havana",
34 "Europe/Lisbon",
35 "Europe/Paris",
36 "Asia/Tokyo",
37 "Asia/Sakhalin",
38 "Africa/Cairo",
39 "Africa/Windhoek",
40 "Australia/Sydney",
41 "Etc/GMT+8"
42 };
43
44 class TestZIDEnumeration : public StringEnumeration {
45 public:
46 TestZIDEnumeration(UBool all = FALSE);
47 ~TestZIDEnumeration();
48
count(UErrorCode &) const49 virtual int32_t count(UErrorCode& /*status*/) const {
50 return len;
51 }
52 virtual const UnicodeString *snext(UErrorCode& status);
53 virtual void reset(UErrorCode& status);
getStaticClassID()54 static inline UClassID getStaticClassID() {
55 return (UClassID)&fgClassID;
56 }
getDynamicClassID() const57 virtual UClassID getDynamicClassID() const {
58 return getStaticClassID();
59 }
60 private:
61 static const char fgClassID;
62 int32_t idx;
63 int32_t len;
64 StringEnumeration *tzenum;
65 };
66
67 const char TestZIDEnumeration::fgClassID = 0;
68
TestZIDEnumeration(UBool all)69 TestZIDEnumeration::TestZIDEnumeration(UBool all)
70 : idx(0) {
71 UErrorCode status = U_ZERO_ERROR;
72 if (all) {
73 tzenum = TimeZone::createEnumeration();
74 len = tzenum->count(status);
75 } else {
76 tzenum = NULL;
77 len = (int32_t)sizeof(TESTZIDS)/sizeof(TESTZIDS[0]);
78 }
79 }
80
~TestZIDEnumeration()81 TestZIDEnumeration::~TestZIDEnumeration() {
82 if (tzenum != NULL) {
83 delete tzenum;
84 }
85 }
86
87 const UnicodeString*
snext(UErrorCode & status)88 TestZIDEnumeration::snext(UErrorCode& status) {
89 if (tzenum != NULL) {
90 return tzenum->snext(status);
91 } else if (U_SUCCESS(status) && idx < len) {
92 unistr = UnicodeString(TESTZIDS[idx++], "");
93 return &unistr;
94 }
95 return NULL;
96 }
97
98 void
reset(UErrorCode & status)99 TestZIDEnumeration::reset(UErrorCode& status) {
100 if (tzenum != NULL) {
101 tzenum->reset(status);
102 } else {
103 idx = 0;
104 }
105 }
106
107
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)108 void TimeZoneRuleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
109 {
110 if (exec) {
111 logln("TestSuite TestTimeZoneRule");
112 }
113 switch (index) {
114 CASE(0, TestSimpleRuleBasedTimeZone);
115 CASE(1, TestHistoricalRuleBasedTimeZone);
116 CASE(2, TestOlsonTransition);
117 CASE(3, TestRBTZTransition);
118 CASE(4, TestHasEquivalentTransitions);
119 CASE(5, TestVTimeZoneRoundTrip);
120 CASE(6, TestVTimeZoneRoundTripPartial);
121 CASE(7, TestVTimeZoneSimpleWrite);
122 CASE(8, TestVTimeZoneHeaderProps);
123 CASE(9, TestGetSimpleRules);
124 CASE(10, TestTimeZoneRuleCoverage);
125 CASE(11, TestSimpleTimeZoneCoverage);
126 CASE(12, TestVTimeZoneCoverage);
127 CASE(13, TestVTimeZoneParse);
128 default: name = ""; break;
129 }
130 }
131
132 /*
133 * Compare SimpleTimeZone with equivalent RBTZ
134 */
135 void
TestSimpleRuleBasedTimeZone(void)136 TimeZoneRuleTest::TestSimpleRuleBasedTimeZone(void) {
137 UErrorCode status = U_ZERO_ERROR;
138 SimpleTimeZone stz(-1*HOUR, "TestSTZ",
139 UCAL_SEPTEMBER, -30, -UCAL_SATURDAY, 1*HOUR, SimpleTimeZone::WALL_TIME,
140 UCAL_FEBRUARY, 2, UCAL_SUNDAY, 1*HOUR, SimpleTimeZone::WALL_TIME,
141 1*HOUR, status);
142 if (U_FAILURE(status)) {
143 errln("FAIL: Couldn't create SimpleTimezone.");
144 }
145
146 DateTimeRule *dtr;
147 AnnualTimeZoneRule *atzr;
148 int32_t STARTYEAR = 2000;
149
150 InitialTimeZoneRule *ir = new InitialTimeZoneRule(
151 "RBTZ_Initial", // Initial time Name
152 -1*HOUR, // Raw offset
153 1*HOUR); // DST saving amount
154
155 // Original rules
156 RuleBasedTimeZone *rbtz1 = new RuleBasedTimeZone("RBTZ1", ir->clone());
157 dtr = new DateTimeRule(UCAL_SEPTEMBER, 30, UCAL_SATURDAY, FALSE,
158 1*HOUR, DateTimeRule::WALL_TIME); // SUN<=30 in September, at 1AM wall time
159 atzr = new AnnualTimeZoneRule("RBTZ_DST1",
160 -1*HOUR /*rawOffset*/, 1*HOUR /*dstSavings*/, dtr,
161 STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
162 rbtz1->addTransitionRule(atzr, status);
163 if (U_FAILURE(status)) {
164 errln("FAIL: couldn't add AnnualTimeZoneRule 1-1.");
165 }
166 dtr = new DateTimeRule(UCAL_FEBRUARY, 2, UCAL_SUNDAY,
167 1*HOUR, DateTimeRule::WALL_TIME); // 2nd Sunday in February, at 1AM wall time
168 atzr = new AnnualTimeZoneRule("RBTZ_STD1",
169 -1*HOUR /*rawOffset*/, 0 /*dstSavings*/, dtr,
170 STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
171 rbtz1->addTransitionRule(atzr, status);
172 if (U_FAILURE(status)) {
173 errln("FAIL: couldn't add AnnualTimeZoneRule 1-2.");
174 }
175 rbtz1->complete(status);
176 if (U_FAILURE(status)) {
177 errln("FAIL: couldn't complete RBTZ 1.");
178 }
179
180 // Equivalent, but different date rule type
181 RuleBasedTimeZone *rbtz2 = new RuleBasedTimeZone("RBTZ2", ir->clone());
182 dtr = new DateTimeRule(UCAL_SEPTEMBER, -1, UCAL_SATURDAY,
183 1*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in September at 1AM wall time
184 atzr = new AnnualTimeZoneRule("RBTZ_DST2", -1*HOUR, 1*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
185 rbtz2->addTransitionRule(atzr, status);
186 if (U_FAILURE(status)) {
187 errln("FAIL: couldn't add AnnualTimeZoneRule 2-1.");
188 }
189 dtr = new DateTimeRule(UCAL_FEBRUARY, 8, UCAL_SUNDAY, true,
190 1*HOUR, DateTimeRule::WALL_TIME); // SUN>=8 in February, at 1AM wall time
191 atzr = new AnnualTimeZoneRule("RBTZ_STD2", -1*HOUR, 0, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
192 rbtz2->addTransitionRule(atzr, status);
193 if (U_FAILURE(status)) {
194 errln("FAIL: couldn't add AnnualTimeZoneRule 2-2.");
195 }
196 rbtz2->complete(status);
197 if (U_FAILURE(status)) {
198 errln("FAIL: couldn't complete RBTZ 2");
199 }
200
201 // Equivalent, but different time rule type
202 RuleBasedTimeZone *rbtz3 = new RuleBasedTimeZone("RBTZ3", ir->clone());
203 dtr = new DateTimeRule(UCAL_SEPTEMBER, 30, UCAL_SATURDAY, false,
204 2*HOUR, DateTimeRule::UTC_TIME);
205 atzr = new AnnualTimeZoneRule("RBTZ_DST3", -1*HOUR, 1*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
206 rbtz3->addTransitionRule(atzr, status);
207 if (U_FAILURE(status)) {
208 errln("FAIL: couldn't add AnnualTimeZoneRule 3-1.");
209 }
210 dtr = new DateTimeRule(UCAL_FEBRUARY, 2, UCAL_SUNDAY,
211 0*HOUR, DateTimeRule::STANDARD_TIME);
212 atzr = new AnnualTimeZoneRule("RBTZ_STD3", -1*HOUR, 0, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
213 rbtz3->addTransitionRule(atzr, status);
214 if (U_FAILURE(status)) {
215 errln("FAIL: couldn't add AnnualTimeZoneRule 3-2.");
216 }
217 rbtz3->complete(status);
218 if (U_FAILURE(status)) {
219 errln("FAIL: couldn't complete RBTZ 3");
220 }
221
222 // Check equivalency for 10 years
223 UDate start = getUTCMillis(STARTYEAR, UCAL_JANUARY, 1);
224 UDate until = getUTCMillis(STARTYEAR + 10, UCAL_JANUARY, 1);
225
226 if (!(stz.hasEquivalentTransitions(*rbtz1, start, until, TRUE, status))) {
227 errln("FAIL: rbtz1 must be equivalent to the SimpleTimeZone in the time range.");
228 }
229 if (U_FAILURE(status)) {
230 errln("FAIL: error returned from hasEquivalentTransitions");
231 }
232 if (!(stz.hasEquivalentTransitions(*rbtz2, start, until, TRUE, status))) {
233 errln("FAIL: rbtz2 must be equivalent to the SimpleTimeZone in the time range.");
234 }
235 if (U_FAILURE(status)) {
236 errln("FAIL: error returned from hasEquivalentTransitions");
237 }
238 if (!(stz.hasEquivalentTransitions(*rbtz3, start, until, TRUE, status))) {
239 errln("FAIL: rbtz3 must be equivalent to the SimpleTimeZone in the time range.");
240 }
241 if (U_FAILURE(status)) {
242 errln("FAIL: error returned from hasEquivalentTransitions");
243 }
244
245 // hasSameRules
246 if (rbtz1->hasSameRules(*rbtz2)) {
247 errln("FAIL: rbtz1 and rbtz2 have different rules, but returned true.");
248 }
249 if (rbtz1->hasSameRules(*rbtz3)) {
250 errln("FAIL: rbtz1 and rbtz3 have different rules, but returned true.");
251 }
252 RuleBasedTimeZone *rbtz1c = (RuleBasedTimeZone*)rbtz1->clone();
253 if (!rbtz1->hasSameRules(*rbtz1c)) {
254 errln("FAIL: Cloned RuleBasedTimeZone must have the same rules with the original.");
255 }
256
257 // getOffset
258 int32_t era, year, month, dayOfMonth, dayOfWeek, millisInDay;
259 UDate time;
260 int32_t offset, dstSavings;
261 UBool dst;
262
263 GregorianCalendar *cal = new GregorianCalendar(status);
264 if (U_FAILURE(status)) {
265 errln("FAIL: Could not create a Gregorian calendar instance.");
266 }
267 cal->setTimeZone(*rbtz1);
268 cal->clear();
269
270 // Jan 1, 1000 BC
271 cal->set(UCAL_ERA, GregorianCalendar::BC);
272 cal->set(1000, UCAL_JANUARY, 1);
273
274 era = cal->get(UCAL_ERA, status);
275 year = cal->get(UCAL_YEAR, status);
276 month = cal->get(UCAL_MONTH, status);
277 dayOfMonth = cal->get(UCAL_DAY_OF_MONTH, status);
278 dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status);
279 millisInDay = cal->get(UCAL_MILLISECONDS_IN_DAY, status);
280 time = cal->getTime(status);
281 if (U_FAILURE(status)) {
282 errln("FAIL: Could not get calendar field values.");
283 }
284 offset = rbtz1->getOffset(era, year, month, dayOfMonth, dayOfWeek, millisInDay, status);
285 if (U_FAILURE(status)) {
286 errln("FAIL: getOffset(7 args) failed.");
287 }
288 if (offset != 0) {
289 errln(UnicodeString("FAIL: Invalid time zone offset: ") + offset + " /expected: 0");
290 }
291 dst = rbtz1->inDaylightTime(time, status);
292 if (U_FAILURE(status)) {
293 errln("FAIL: inDaylightTime failed.");
294 }
295 if (!dst) {
296 errln("FAIL: Invalid daylight saving time");
297 }
298 rbtz1->getOffset(time, TRUE, offset, dstSavings, status);
299 if (U_FAILURE(status)) {
300 errln("FAIL: getOffset(5 args) failed.");
301 }
302 if (offset != -3600000) {
303 errln(UnicodeString("FAIL: Invalid time zone raw offset: ") + offset + " /expected: -3600000");
304 }
305 if (dstSavings != 3600000) {
306 errln(UnicodeString("FAIL: Invalid DST amount: ") + dstSavings + " /expected: 3600000");
307 }
308
309 // July 1, 2000, AD
310 cal->set(UCAL_ERA, GregorianCalendar::AD);
311 cal->set(2000, UCAL_JULY, 1);
312
313 era = cal->get(UCAL_ERA, status);
314 year = cal->get(UCAL_YEAR, status);
315 month = cal->get(UCAL_MONTH, status);
316 dayOfMonth = cal->get(UCAL_DAY_OF_MONTH, status);
317 dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status);
318 millisInDay = cal->get(UCAL_MILLISECONDS_IN_DAY, status);
319 time = cal->getTime(status);
320 if (U_FAILURE(status)) {
321 errln("FAIL: Could not get calendar field values.");
322 }
323 offset = rbtz1->getOffset(era, year, month, dayOfMonth, dayOfWeek, millisInDay, status);
324 if (U_FAILURE(status)) {
325 errln("FAIL: getOffset(7 args) failed.");
326 }
327 if (offset != -3600000) {
328 errln((UnicodeString)"FAIL: Invalid time zone offset: " + offset + " /expected: -3600000");
329 }
330 dst = rbtz1->inDaylightTime(time, status);
331 if (U_FAILURE(status)) {
332 errln("FAIL: inDaylightTime failed.");
333 }
334 if (dst) {
335 errln("FAIL: Invalid daylight saving time");
336 }
337 rbtz1->getOffset(time, TRUE, offset, dstSavings, status);
338 if (U_FAILURE(status)) {
339 errln("FAIL: getOffset(5 args) failed.");
340 }
341 if (offset != -3600000) {
342 errln((UnicodeString)"FAIL: Invalid time zone raw offset: " + offset + " /expected: -3600000");
343 }
344 if (dstSavings != 0) {
345 errln((UnicodeString)"FAIL: Invalid DST amount: " + dstSavings + " /expected: 0");
346 }
347
348 // getRawOffset
349 offset = rbtz1->getRawOffset();
350 if (offset != -1*HOUR) {
351 errln((UnicodeString)"FAIL: Invalid time zone raw offset returned by getRawOffset: "
352 + offset + " /expected: -3600000");
353 }
354
355 // operator=/==/!=
356 RuleBasedTimeZone rbtz0("RBTZ1", ir->clone());
357 if (rbtz0 == *rbtz1 || !(rbtz0 != *rbtz1)) {
358 errln("FAIL: RuleBasedTimeZone rbtz0 is not equal to rbtz1, but got wrong result");
359 }
360 rbtz0 = *rbtz1;
361 if (rbtz0 != *rbtz1 || !(rbtz0 == *rbtz1)) {
362 errln("FAIL: RuleBasedTimeZone rbtz0 is equal to rbtz1, but got wrong result");
363 }
364
365 // setRawOffset
366 const int32_t RAW = -10*HOUR;
367 rbtz0.setRawOffset(RAW);
368 if (rbtz0.getRawOffset() != RAW) {
369 logln("setRawOffset is implemented in RuleBasedTimeZone");
370 }
371
372 // useDaylightTime
373 if (!rbtz1->useDaylightTime()) {
374 errln("FAIL: useDaylightTime returned FALSE");
375 }
376
377 // Try to add 3rd final rule
378 dtr = new DateTimeRule(UCAL_OCTOBER, 15, 1*HOUR, DateTimeRule::WALL_TIME);
379 atzr = new AnnualTimeZoneRule("3RD_ATZ", -1*HOUR, 2*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
380 rbtz1->addTransitionRule(atzr, status);
381 if (U_SUCCESS(status)) {
382 errln("FAIL: 3rd final rule must be rejected");
383 } else {
384 delete atzr;
385 }
386
387 // Try to add an initial rule
388 InitialTimeZoneRule *ir1 = new InitialTimeZoneRule("Test Initial", 2*HOUR, 0);
389 rbtz1->addTransitionRule(ir1, status);
390 if (U_SUCCESS(status)) {
391 errln("FAIL: InitialTimeZoneRule must be rejected");
392 } else {
393 delete ir1;
394 }
395
396 delete ir;
397 delete rbtz1;
398 delete rbtz2;
399 delete rbtz3;
400 delete rbtz1c;
401 delete cal;
402 }
403
404 /*
405 * Test equivalency between OlsonTimeZone and custom RBTZ representing the
406 * equivalent rules in a certain time range
407 */
408 void
TestHistoricalRuleBasedTimeZone(void)409 TimeZoneRuleTest::TestHistoricalRuleBasedTimeZone(void) {
410 UErrorCode status = U_ZERO_ERROR;
411
412 // Compare to America/New_York with equivalent RBTZ
413 BasicTimeZone *ny = (BasicTimeZone*)TimeZone::createTimeZone("America/New_York");
414
415 //RBTZ
416 InitialTimeZoneRule *ir = new InitialTimeZoneRule("EST", -5*HOUR, 0);
417 RuleBasedTimeZone *rbtz = new RuleBasedTimeZone("EST5EDT", ir);
418
419 DateTimeRule *dtr;
420 AnnualTimeZoneRule *tzr;
421
422 // Standard time
423 dtr = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SUNDAY,
424 2*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in October, at 2AM wall time
425 tzr = new AnnualTimeZoneRule("EST", -5*HOUR /*rawOffset*/, 0 /*dstSavings*/, dtr, 1967, 2006);
426 rbtz->addTransitionRule(tzr, status);
427 if (U_FAILURE(status)) {
428 errln("FAIL: couldn't add AnnualTimeZoneRule 1.");
429 }
430
431 dtr = new DateTimeRule(UCAL_NOVEMBER, 1, UCAL_SUNDAY,
432 true, 2*HOUR, DateTimeRule::WALL_TIME); // SUN>=1 in November, at 2AM wall time
433 tzr = new AnnualTimeZoneRule("EST", -5*HOUR, 0, dtr, 2007, AnnualTimeZoneRule::MAX_YEAR);
434 rbtz->addTransitionRule(tzr, status);
435 if (U_FAILURE(status)) {
436 errln("FAIL: couldn't add AnnualTimeZoneRule 2.");
437 }
438
439 // Daylight saving time
440 dtr = new DateTimeRule(UCAL_APRIL, -1, UCAL_SUNDAY,
441 2*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in April, at 2AM wall time
442 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1967, 1973);
443 rbtz->addTransitionRule(tzr, status);
444 if (U_FAILURE(status)) {
445 errln("FAIL: couldn't add AnnualTimeZoneRule 3.");
446 }
447
448 dtr = new DateTimeRule(UCAL_JANUARY, 6,
449 2*HOUR, DateTimeRule::WALL_TIME); // January 6, at 2AM wall time
450 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1974, 1974);
451 rbtz->addTransitionRule(tzr, status);
452 if (U_FAILURE(status)) {
453 errln("FAIL: couldn't add AnnualTimeZoneRule 4.");
454 }
455
456 dtr = new DateTimeRule(UCAL_FEBRUARY, 23,
457 2*HOUR, DateTimeRule::WALL_TIME); // February 23, at 2AM wall time
458 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1975, 1975);
459 rbtz->addTransitionRule(tzr, status);
460 if (U_FAILURE(status)) {
461 errln("FAIL: couldn't add AnnualTimeZoneRule 5.");
462 }
463
464 dtr = new DateTimeRule(UCAL_APRIL, -1, UCAL_SUNDAY,
465 2*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in April, at 2AM wall time
466 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1976, 1986);
467 rbtz->addTransitionRule(tzr, status);
468 if (U_FAILURE(status)) {
469 errln("FAIL: couldn't add AnnualTimeZoneRule 6.");
470 }
471
472 dtr = new DateTimeRule(UCAL_APRIL, 1, UCAL_SUNDAY,
473 true, 2*HOUR, DateTimeRule::WALL_TIME); // SUN>=1 in April, at 2AM wall time
474 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1987, 2006);
475 rbtz->addTransitionRule(tzr, status);
476 if (U_FAILURE(status)) {
477 errln("FAIL: couldn't add AnnualTimeZoneRule 7.");
478 }
479
480 dtr = new DateTimeRule(UCAL_MARCH, 8, UCAL_SUNDAY,
481 true, 2*HOUR, DateTimeRule::WALL_TIME); // SUN>=8 in March, at 2AM wall time
482 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 2007, AnnualTimeZoneRule::MAX_YEAR);
483 rbtz->addTransitionRule(tzr, status);
484 if (U_FAILURE(status)) {
485 errln("FAIL: couldn't add AnnualTimeZoneRule 7.");
486 }
487
488 rbtz->complete(status);
489 if (U_FAILURE(status)) {
490 errln("FAIL: couldn't complete RBTZ.");
491 }
492
493 // hasEquivalentTransitions
494 UDate jan1_1950 = getUTCMillis(1950, UCAL_JANUARY, 1);
495 UDate jan1_1967 = getUTCMillis(1971, UCAL_JANUARY, 1);
496 UDate jan1_2010 = getUTCMillis(2010, UCAL_JANUARY, 1);
497
498 if (!ny->hasEquivalentTransitions(*rbtz, jan1_1967, jan1_2010, TRUE, status)) {
499 errln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010");
500 }
501 if (U_FAILURE(status)) {
502 errln("FAIL: error returned from hasEquivalentTransitions for ny/rbtz 1967-2010");
503 }
504 if (ny->hasEquivalentTransitions(*rbtz, jan1_1950, jan1_2010, TRUE, status)) {
505 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010");
506 }
507 if (U_FAILURE(status)) {
508 errln("FAIL: error returned from hasEquivalentTransitions for ny/rbtz 1950-2010");
509 }
510
511 // Same with above, but calling RBTZ#hasEquivalentTransitions against OlsonTimeZone
512 if (!rbtz->hasEquivalentTransitions(*ny, jan1_1967, jan1_2010, TRUE, status)) {
513 errln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010");
514 }
515 if (U_FAILURE(status)) {
516 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/ny 1967-2010");
517 }
518 if (rbtz->hasEquivalentTransitions(*ny, jan1_1950, jan1_2010, TRUE, status)) {
519 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010");
520 }
521 if (U_FAILURE(status)) {
522 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/ny 1950-2010");
523 }
524
525 // TimeZone APIs
526 if (ny->hasSameRules(*rbtz) || rbtz->hasSameRules(*ny)) {
527 errln("FAIL: hasSameRules must return false");
528 }
529 RuleBasedTimeZone *rbtzc = (RuleBasedTimeZone*)rbtz->clone();
530 if (!rbtz->hasSameRules(*rbtzc) || !rbtz->hasEquivalentTransitions(*rbtzc, jan1_1950, jan1_2010, TRUE, status)) {
531 errln("FAIL: hasSameRules/hasEquivalentTransitions must return true for cloned RBTZs");
532 }
533 if (U_FAILURE(status)) {
534 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/rbtzc 1950-2010");
535 }
536
537 UDate times[] = {
538 getUTCMillis(2006, UCAL_MARCH, 15),
539 getUTCMillis(2006, UCAL_NOVEMBER, 1),
540 getUTCMillis(2007, UCAL_MARCH, 15),
541 getUTCMillis(2007, UCAL_NOVEMBER, 1),
542 getUTCMillis(2008, UCAL_MARCH, 15),
543 getUTCMillis(2008, UCAL_NOVEMBER, 1),
544 0
545 };
546 int32_t offset1, dst1;
547 int32_t offset2, dst2;
548
549 for (int i = 0; times[i] != 0; i++) {
550 // Check getOffset - must return the same results for these time data
551 rbtz->getOffset(times[i], FALSE, offset1, dst1, status);
552 if (U_FAILURE(status)) {
553 errln("FAIL: rbtz->getOffset failed");
554 }
555 ny->getOffset(times[i], FALSE, offset2, dst2, status);
556 if (U_FAILURE(status)) {
557 errln("FAIL: ny->getOffset failed");
558 }
559 if (offset1 != offset2 || dst1 != dst2) {
560 errln("FAIL: Incompatible time zone offset/dstSavings for ny and rbtz");
561 }
562
563 // Check inDaylightTime
564 if (rbtz->inDaylightTime(times[i], status) != ny->inDaylightTime(times[i], status)) {
565 errln("FAIL: Incompatible daylight saving time for ny and rbtz");
566 }
567 if (U_FAILURE(status)) {
568 errln("FAIL: inDaylightTime failed");
569 }
570 }
571
572 delete ny;
573 delete rbtz;
574 delete rbtzc;
575 }
576
577 /*
578 * Check if transitions returned by getNextTransition/getPreviousTransition
579 * are actual time transitions.
580 */
581 void
TestOlsonTransition(void)582 TimeZoneRuleTest::TestOlsonTransition(void) {
583
584 const int32_t TESTYEARS[][2] = {
585 {1895, 1905}, // including int32 minimum second
586 {1965, 1975}, // including the epoch
587 {1995, 2015}, // practical year range
588 {0,0}
589 };
590
591 UErrorCode status = U_ZERO_ERROR;
592 TestZIDEnumeration tzenum(!quick);
593 while (TRUE) {
594 const UnicodeString *tzid = tzenum.snext(status);
595 if (tzid == NULL) {
596 break;
597 }
598 if (U_FAILURE(status)) {
599 errln("FAIL: error returned while enumerating timezone IDs.");
600 break;
601 }
602 BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
603 for (int32_t i = 0; TESTYEARS[i][0] != 0 || TESTYEARS[i][1] != 0; i++) {
604 UDate lo = getUTCMillis(TESTYEARS[i][0], UCAL_JANUARY, 1);
605 UDate hi = getUTCMillis(TESTYEARS[i][1], UCAL_JANUARY, 1);
606 verifyTransitions(*tz, lo, hi);
607 }
608 delete tz;
609 }
610 }
611
612 /*
613 * Check if an OlsonTimeZone and its equivalent RBTZ have the exact same
614 * transitions.
615 */
616 void
TestRBTZTransition(void)617 TimeZoneRuleTest::TestRBTZTransition(void) {
618 const int32_t STARTYEARS[] = {
619 1900,
620 1960,
621 1990,
622 2010,
623 0
624 };
625
626 UErrorCode status = U_ZERO_ERROR;
627 TestZIDEnumeration tzenum(!quick);
628 while (TRUE) {
629 const UnicodeString *tzid = tzenum.snext(status);
630 if (tzid == NULL) {
631 break;
632 }
633 if (U_FAILURE(status)) {
634 errln("FAIL: error returned while enumerating timezone IDs.");
635 break;
636 }
637 BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
638 int32_t ruleCount = tz->countTransitionRules(status);
639
640 const InitialTimeZoneRule *initial;
641 const TimeZoneRule **trsrules = new const TimeZoneRule*[ruleCount];
642 tz->getTimeZoneRules(initial, trsrules, ruleCount, status);
643 if (U_FAILURE(status)) {
644 errln((UnicodeString)"FAIL: failed to get the TimeZoneRules from time zone " + *tzid);
645 }
646 RuleBasedTimeZone *rbtz = new RuleBasedTimeZone(*tzid, initial->clone());
647 if (U_FAILURE(status)) {
648 errln((UnicodeString)"FAIL: failed to get the transition rule count from time zone " + *tzid);
649 }
650 for (int32_t i = 0; i < ruleCount; i++) {
651 rbtz->addTransitionRule(trsrules[i]->clone(), status);
652 if (U_FAILURE(status)) {
653 errln((UnicodeString)"FAIL: failed to add a transition rule at index " + i + " to the RBTZ for " + *tzid);
654 }
655 }
656 rbtz->complete(status);
657 if (U_FAILURE(status)) {
658 errln((UnicodeString)"FAIL: complete() failed for the RBTZ for " + *tzid);
659 }
660
661 for (int32_t idx = 0; STARTYEARS[idx] != 0; idx++) {
662 UDate start = getUTCMillis(STARTYEARS[idx], UCAL_JANUARY, 1);
663 UDate until = getUTCMillis(STARTYEARS[idx] + 20, UCAL_JANUARY, 1);
664 // Compare the original OlsonTimeZone with the RBTZ starting the startTime for 20 years
665
666 // Ascending
667 compareTransitionsAscending(*tz, *rbtz, start, until, FALSE);
668 // Ascending/inclusive
669 compareTransitionsAscending(*tz, *rbtz, start + 1, until, TRUE);
670 // Descending
671 compareTransitionsDescending(*tz, *rbtz, start, until, FALSE);
672 // Descending/inclusive
673 compareTransitionsDescending(*tz, *rbtz, start + 1, until, TRUE);
674 }
675 delete [] trsrules;
676 delete rbtz;
677 delete tz;
678 }
679 }
680
681 void
TestHasEquivalentTransitions(void)682 TimeZoneRuleTest::TestHasEquivalentTransitions(void) {
683 // America/New_York and America/Indiana/Indianapolis are equivalent
684 // since 2006
685 UErrorCode status = U_ZERO_ERROR;
686 BasicTimeZone *newyork = (BasicTimeZone*)TimeZone::createTimeZone("America/New_York");
687 BasicTimeZone *indianapolis = (BasicTimeZone*)TimeZone::createTimeZone("America/Indiana/Indianapolis");
688 BasicTimeZone *gmt_5 = (BasicTimeZone*)TimeZone::createTimeZone("Etc/GMT+5");
689
690 UDate jan1_1971 = getUTCMillis(1971, UCAL_JANUARY, 1);
691 UDate jan1_2005 = getUTCMillis(2005, UCAL_JANUARY, 1);
692 UDate jan1_2006 = getUTCMillis(2006, UCAL_JANUARY, 1);
693 UDate jan1_2007 = getUTCMillis(2007, UCAL_JANUARY, 1);
694 UDate jan1_2011 = getUTCMillis(2010, UCAL_JANUARY, 1);
695
696 if (newyork->hasEquivalentTransitions(*indianapolis, jan1_2005, jan1_2011, TRUE, status)) {
697 errln("FAIL: New_York is not equivalent to Indianapolis between 2005 and 2010");
698 }
699 if (U_FAILURE(status)) {
700 errln("FAIL: error status is returned from hasEquivalentTransition");
701 }
702 if (!newyork->hasEquivalentTransitions(*indianapolis, jan1_2006, jan1_2011, TRUE, status)) {
703 errln("FAIL: New_York is equivalent to Indianapolis between 2006 and 2010");
704 }
705 if (U_FAILURE(status)) {
706 errln("FAIL: error status is returned from hasEquivalentTransition");
707 }
708
709 if (!indianapolis->hasEquivalentTransitions(*gmt_5, jan1_1971, jan1_2006, TRUE, status)) {
710 errln("FAIL: Indianapolis is equivalent to GMT+5 between 1971 and 2005");
711 }
712 if (U_FAILURE(status)) {
713 errln("FAIL: error status is returned from hasEquivalentTransition");
714 }
715 if (indianapolis->hasEquivalentTransitions(*gmt_5, jan1_1971, jan1_2007, TRUE, status)) {
716 errln("FAIL: Indianapolis is not equivalent to GMT+5 between 1971 and 2006");
717 }
718 if (U_FAILURE(status)) {
719 errln("FAIL: error status is returned from hasEquivalentTransition");
720 }
721
722 // Cloned TimeZone
723 BasicTimeZone *newyork2 = (BasicTimeZone*)newyork->clone();
724 if (!newyork->hasEquivalentTransitions(*newyork2, jan1_1971, jan1_2011, FALSE, status)) {
725 errln("FAIL: Cloned TimeZone must have the same transitions");
726 }
727 if (U_FAILURE(status)) {
728 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/newyork2");
729 }
730 if (!newyork->hasEquivalentTransitions(*newyork2, jan1_1971, jan1_2011, TRUE, status)) {
731 errln("FAIL: Cloned TimeZone must have the same transitions");
732 }
733 if (U_FAILURE(status)) {
734 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/newyork2");
735 }
736
737 // America/New_York and America/Los_Angeles has same DST start rules, but
738 // raw offsets are different
739 BasicTimeZone *losangeles = (BasicTimeZone*)TimeZone::createTimeZone("America/Los_Angeles");
740 if (newyork->hasEquivalentTransitions(*losangeles, jan1_2006, jan1_2011, TRUE, status)) {
741 errln("FAIL: New_York is not equivalent to Los Angeles, but returned true");
742 }
743 if (U_FAILURE(status)) {
744 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/losangeles");
745 }
746
747 delete newyork;
748 delete newyork2;
749 delete indianapolis;
750 delete gmt_5;
751 delete losangeles;
752 }
753
754 /*
755 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format, create a new
756 * VTimeZone from the VTIMEZONE data, then compare transitions
757 */
758 void
TestVTimeZoneRoundTrip(void)759 TimeZoneRuleTest::TestVTimeZoneRoundTrip(void) {
760 UDate startTime = getUTCMillis(1850, UCAL_JANUARY, 1);
761 UDate endTime = getUTCMillis(2050, UCAL_JANUARY, 1);
762
763 UErrorCode status = U_ZERO_ERROR;
764 TestZIDEnumeration tzenum(!quick);
765 while (TRUE) {
766 const UnicodeString *tzid = tzenum.snext(status);
767 if (tzid == NULL) {
768 break;
769 }
770 if (U_FAILURE(status)) {
771 errln("FAIL: error returned while enumerating timezone IDs.");
772 break;
773 }
774 BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
775 VTimeZone *vtz_org = VTimeZone::createVTimeZoneByID(*tzid);
776 vtz_org->setTZURL("http://source.icu-project.org/timezone");
777 vtz_org->setLastModified(Calendar::getNow());
778 VTimeZone *vtz_new = NULL;
779 UnicodeString vtzdata;
780 // Write out VTIMEZONE data
781 vtz_org->write(vtzdata, status);
782 if (U_FAILURE(status)) {
783 errln((UnicodeString)"FAIL: error returned while writing time zone rules for " +
784 *tzid + " into VTIMEZONE format.");
785 } else {
786 // Read VTIMEZONE data
787 vtz_new = VTimeZone::createVTimeZone(vtzdata, status);
788 if (U_FAILURE(status)) {
789 errln((UnicodeString)"FAIL: error returned while reading VTIMEZONE data for " + *tzid);
790 } else {
791 // Write out VTIMEZONE one more time
792 UnicodeString vtzdata1;
793 vtz_new->write(vtzdata1, status);
794 if (U_FAILURE(status)) {
795 errln((UnicodeString)"FAIL: error returned while writing time zone rules for " +
796 *tzid + "(vtz_new) into VTIMEZONE format.");
797 } else {
798 // Make sure VTIMEZONE data is exactly same with the first one
799 if (vtzdata != vtzdata1) {
800 errln((UnicodeString)"FAIL: different VTIMEZONE data after round trip for " + *tzid);
801 }
802 }
803 // Check equivalency after the first transition.
804 // The DST information before the first transition might be lost
805 // because there is no good way to represent the initial time with
806 // VTIMEZONE.
807 int32_t raw1, raw2, dst1, dst2;
808 tz->getOffset(startTime, FALSE, raw1, dst1, status);
809 vtz_new->getOffset(startTime, FALSE, raw2, dst2, status);
810 if (U_FAILURE(status)) {
811 errln("FAIL: error status is returned from getOffset");
812 } else {
813 if (raw1 + dst1 != raw2 + dst2) {
814 errln("FAIL: VTimeZone for " + *tzid +
815 " is not equivalent to its OlsonTimeZone corresponding at "
816 + dateToString(startTime));
817 }
818 TimeZoneTransition trans;
819 UBool avail = tz->getNextTransition(startTime, FALSE, trans);
820 if (avail) {
821 if (!vtz_new->hasEquivalentTransitions(*tz, trans.getTime(),
822 endTime, TRUE, status)) {
823 errln("FAIL: VTimeZone for " + *tzid +
824 " is not equivalent to its OlsonTimeZone corresponding.");
825 }
826 if (U_FAILURE(status)) {
827 errln("FAIL: error status is returned from hasEquivalentTransition");
828 }
829 }
830 }
831 }
832 if (vtz_new != NULL) {
833 delete vtz_new;
834 vtz_new = NULL;
835 }
836 }
837 delete tz;
838 delete vtz_org;
839 }
840 }
841
842 /*
843 * Write out time zone rules of OlsonTimeZone after a cutover date into VTIMEZONE format,
844 * create a new VTimeZone from the VTIMEZONE data, then compare transitions
845 */
846 void
TestVTimeZoneRoundTripPartial(void)847 TimeZoneRuleTest::TestVTimeZoneRoundTripPartial(void) {
848 const int32_t STARTYEARS[] = {
849 1900,
850 1950,
851 2020,
852 0
853 };
854 UDate endTime = getUTCMillis(2050, UCAL_JANUARY, 1);
855
856 UErrorCode status = U_ZERO_ERROR;
857 TestZIDEnumeration tzenum(!quick);
858 while (TRUE) {
859 const UnicodeString *tzid = tzenum.snext(status);
860 if (tzid == NULL) {
861 break;
862 }
863 if (U_FAILURE(status)) {
864 errln("FAIL: error returned while enumerating timezone IDs.");
865 break;
866 }
867 BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
868 VTimeZone *vtz_org = VTimeZone::createVTimeZoneByID(*tzid);
869 VTimeZone *vtz_new = NULL;
870 UnicodeString vtzdata;
871
872 for (int32_t i = 0; STARTYEARS[i] != 0; i++) {
873 // Write out VTIMEZONE
874 UDate startTime = getUTCMillis(STARTYEARS[i], UCAL_JANUARY, 1);
875 vtz_org->write(startTime, vtzdata, status);
876 if (U_FAILURE(status)) {
877 errln((UnicodeString)"FAIL: error returned while writing time zone rules for " +
878 *tzid + " into VTIMEZONE format since " + dateToString(startTime));
879 } else {
880 // Read VTIMEZONE data
881 vtz_new = VTimeZone::createVTimeZone(vtzdata, status);
882 if (U_FAILURE(status)) {
883 errln((UnicodeString)"FAIL: error returned while reading VTIMEZONE data for " + *tzid
884 + " since " + dateToString(startTime));
885 } else {
886 // Check equivalency after the first transition.
887 // The DST information before the first transition might be lost
888 // because there is no good way to represent the initial time with
889 // VTIMEZONE.
890 int32_t raw1, raw2, dst1, dst2;
891 tz->getOffset(startTime, FALSE, raw1, dst1, status);
892 vtz_new->getOffset(startTime, FALSE, raw2, dst2, status);
893 if (U_FAILURE(status)) {
894 errln("FAIL: error status is returned from getOffset");
895 } else {
896 if (raw1 + dst1 != raw2 + dst2) {
897 errln("FAIL: VTimeZone for " + *tzid +
898 " is not equivalent to its OlsonTimeZone corresponding at "
899 + dateToString(startTime));
900 }
901 TimeZoneTransition trans;
902 UBool avail = tz->getNextTransition(startTime, FALSE, trans);
903 if (avail) {
904 if (!vtz_new->hasEquivalentTransitions(*tz, trans.getTime(),
905 endTime, TRUE, status)) {
906 errln("FAIL: VTimeZone for " + *tzid +
907 " is not equivalent to its OlsonTimeZone corresponding.");
908 }
909 if (U_FAILURE(status)) {
910 errln("FAIL: error status is returned from hasEquivalentTransition");
911 }
912 }
913 }
914 }
915 }
916 if (vtz_new != NULL) {
917 delete vtz_new;
918 vtz_new = NULL;
919 }
920 }
921 delete tz;
922 delete vtz_org;
923 }
924 }
925
926 /*
927 * Write out simple time zone rules from an OlsonTimeZone at various time into VTIMEZONE
928 * format and create a new VTimeZone from the VTIMEZONE data, then make sure the raw offset
929 * and DST savings are same in these two time zones.
930 */
931 void
TestVTimeZoneSimpleWrite(void)932 TimeZoneRuleTest::TestVTimeZoneSimpleWrite(void) {
933 const int32_t TESTDATES[][3] = {
934 {2006, UCAL_JANUARY, 1},
935 {2006, UCAL_MARCH, 15},
936 {2006, UCAL_MARCH, 31},
937 {2006, UCAL_OCTOBER, 25},
938 {2006, UCAL_NOVEMBER, 1},
939 {2006, UCAL_NOVEMBER, 5},
940 {2007, UCAL_JANUARY, 1},
941 {0, 0, 0}
942 };
943
944 UErrorCode status = U_ZERO_ERROR;
945 TestZIDEnumeration tzenum(!quick);
946 while (TRUE) {
947 const UnicodeString *tzid = tzenum.snext(status);
948 if (tzid == NULL) {
949 break;
950 }
951 if (U_FAILURE(status)) {
952 errln("FAIL: error returned while enumerating timezone IDs.");
953 break;
954 }
955 VTimeZone *vtz_org = VTimeZone::createVTimeZoneByID(*tzid);
956 VTimeZone *vtz_new = NULL;
957 UnicodeString vtzdata;
958
959 for (int32_t i = 0; TESTDATES[i][0] != 0; i++) {
960 // Write out VTIMEZONE
961 UDate time = getUTCMillis(TESTDATES[i][0], TESTDATES[i][1], TESTDATES[i][2]);
962 vtz_org->writeSimple(time, vtzdata, status);
963 if (U_FAILURE(status)) {
964 errln((UnicodeString)"FAIL: error returned while writing simple time zone rules for " +
965 *tzid + " into VTIMEZONE format at " + dateToString(time));
966 } else {
967 // Read VTIMEZONE data
968 vtz_new = VTimeZone::createVTimeZone(vtzdata, status);
969 if (U_FAILURE(status)) {
970 errln((UnicodeString)"FAIL: error returned while reading simple VTIMEZONE data for " + *tzid
971 + " at " + dateToString(time));
972 } else {
973 // Check equivalency
974 int32_t raw0, dst0;
975 int32_t raw1, dst1;
976 vtz_org->getOffset(time, FALSE, raw0, dst0, status);
977 vtz_new->getOffset(time, FALSE, raw1, dst1, status);
978 if (U_SUCCESS(status)) {
979 if (raw0 != raw1 || dst0 != dst1) {
980 errln("FAIL: VTimeZone writeSimple for " + *tzid + " at "
981 + dateToString(time) + " failed to the round trip.");
982 }
983 } else {
984 errln("FAIL: getOffset returns error status");
985 }
986 }
987 }
988 if (vtz_new != NULL) {
989 delete vtz_new;
990 vtz_new = NULL;
991 }
992 }
993 delete vtz_org;
994 }
995 }
996
997 /*
998 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format with RFC2445 header TZURL and
999 * LAST-MODIFIED, create a new VTimeZone from the VTIMEZONE data to see if the headers are preserved.
1000 */
1001 void
TestVTimeZoneHeaderProps(void)1002 TimeZoneRuleTest::TestVTimeZoneHeaderProps(void) {
1003 const UnicodeString TESTURL1("http://source.icu-project.org");
1004 const UnicodeString TESTURL2("http://www.ibm.com");
1005
1006 UErrorCode status = U_ZERO_ERROR;
1007 UnicodeString tzurl;
1008 UDate lmod;
1009 UDate lastmod = getUTCMillis(2007, UCAL_JUNE, 1);
1010 VTimeZone *vtz = VTimeZone::createVTimeZoneByID("America/Chicago");
1011 vtz->setTZURL(TESTURL1);
1012 vtz->setLastModified(lastmod);
1013
1014 // Roundtrip conversion
1015 UnicodeString vtzdata;
1016 vtz->write(vtzdata, status);
1017 VTimeZone *newvtz1 = NULL;
1018 if (U_FAILURE(status)) {
1019 errln("FAIL: error returned while writing VTIMEZONE data 1");
1020 return;
1021 }
1022 // Create a new one
1023 newvtz1 = VTimeZone::createVTimeZone(vtzdata, status);
1024 if (U_FAILURE(status)) {
1025 errln("FAIL: error returned while loading VTIMEZONE data 1");
1026 } else {
1027 // Check if TZURL and LAST-MODIFIED properties are preserved
1028 newvtz1->getTZURL(tzurl);
1029 if (tzurl != TESTURL1) {
1030 errln("FAIL: TZURL 1 was not preserved");
1031 }
1032 vtz->getLastModified(lmod);
1033 if (lastmod != lmod) {
1034 errln("FAIL: LAST-MODIFIED was not preserved");
1035 }
1036 }
1037
1038 if (U_SUCCESS(status)) {
1039 // Set different tzurl
1040 newvtz1->setTZURL(TESTURL2);
1041
1042 // Second roundtrip, with a cutover
1043 newvtz1->write(vtzdata, status);
1044 if (U_FAILURE(status)) {
1045 errln("FAIL: error returned while writing VTIMEZONE data 2");
1046 } else {
1047 VTimeZone *newvtz2 = VTimeZone::createVTimeZone(vtzdata, status);
1048 if (U_FAILURE(status)) {
1049 errln("FAIL: error returned while loading VTIMEZONE data 2");
1050 } else {
1051 // Check if TZURL and LAST-MODIFIED properties are preserved
1052 newvtz2->getTZURL(tzurl);
1053 if (tzurl != TESTURL2) {
1054 errln("FAIL: TZURL was not preserved in the second roundtrip");
1055 }
1056 vtz->getLastModified(lmod);
1057 if (lastmod != lmod) {
1058 errln("FAIL: LAST-MODIFIED was not preserved in the second roundtrip");
1059 }
1060 }
1061 delete newvtz2;
1062 }
1063 }
1064 delete newvtz1;
1065 delete vtz;
1066 }
1067
1068 /*
1069 * Extract simple rules from an OlsonTimeZone and make sure the rule format matches
1070 * the expected format.
1071 */
1072 void
TestGetSimpleRules(void)1073 TimeZoneRuleTest::TestGetSimpleRules(void) {
1074 UDate testTimes[] = {
1075 getUTCMillis(1970, UCAL_JANUARY, 1),
1076 getUTCMillis(2000, UCAL_MARCH, 31),
1077 getUTCMillis(2005, UCAL_JULY, 1),
1078 getUTCMillis(2010, UCAL_NOVEMBER, 1),
1079 };
1080 int32_t numTimes = sizeof(testTimes)/sizeof(UDate);
1081 UErrorCode status = U_ZERO_ERROR;
1082 TestZIDEnumeration tzenum(!quick);
1083 InitialTimeZoneRule *initial;
1084 AnnualTimeZoneRule *std, *dst;
1085 for (int32_t i = 0; i < numTimes ; i++) {
1086 while (TRUE) {
1087 const UnicodeString *tzid = tzenum.snext(status);
1088 if (tzid == NULL) {
1089 break;
1090 }
1091 if (U_FAILURE(status)) {
1092 errln("FAIL: error returned while enumerating timezone IDs.");
1093 break;
1094 }
1095 BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
1096 initial = NULL;
1097 std = dst = NULL;
1098 tz->getSimpleRulesNear(testTimes[i], initial, std, dst, status);
1099 if (U_FAILURE(status)) {
1100 errln("FAIL: getSimpleRules failed.");
1101 break;
1102 }
1103 if (initial == NULL) {
1104 errln("FAIL: initial rule must not be NULL");
1105 break;
1106 } else if (!(std == NULL && dst == NULL || std != NULL && dst != NULL)) {
1107 errln("FAIL: invalid std/dst pair.");
1108 break;
1109 }
1110 if (std != NULL) {
1111 const DateTimeRule *dtr = std->getRule();
1112 if (dtr->getDateRuleType() != DateTimeRule::DOW) {
1113 errln("FAIL: simple std rull must use DateTimeRule::DOW as date rule.");
1114 break;
1115 }
1116 if (dtr->getTimeRuleType() != DateTimeRule::WALL_TIME) {
1117 errln("FAIL: simple std rull must use DateTimeRule::WALL_TIME as time rule.");
1118 break;
1119 }
1120 dtr = dst->getRule();
1121 if (dtr->getDateRuleType() != DateTimeRule::DOW) {
1122 errln("FAIL: simple dst rull must use DateTimeRule::DOW as date rule.");
1123 break;
1124 }
1125 if (dtr->getTimeRuleType() != DateTimeRule::WALL_TIME) {
1126 errln("FAIL: simple dst rull must use DateTimeRule::WALL_TIME as time rule.");
1127 break;
1128 }
1129 }
1130 // Create an RBTZ from the rules and compare the offsets at the date
1131 RuleBasedTimeZone *rbtz = new RuleBasedTimeZone(*tzid, initial);
1132 if (std != NULL) {
1133 rbtz->addTransitionRule(std, status);
1134 if (U_FAILURE(status)) {
1135 errln("FAIL: couldn't add std rule.");
1136 }
1137 rbtz->addTransitionRule(dst, status);
1138 if (U_FAILURE(status)) {
1139 errln("FAIL: couldn't add dst rule.");
1140 }
1141 }
1142 rbtz->complete(status);
1143 if (U_FAILURE(status)) {
1144 errln("FAIL: couldn't complete rbtz for " + *tzid);
1145 }
1146
1147 int32_t raw0, dst0, raw1, dst1;
1148 tz->getOffset(testTimes[i], FALSE, raw0, dst0, status);
1149 if (U_FAILURE(status)) {
1150 errln("FAIL: couldn't get offsets from tz for " + *tzid);
1151 }
1152 rbtz->getOffset(testTimes[i], FALSE, raw1, dst1, status);
1153 if (U_FAILURE(status)) {
1154 errln("FAIL: couldn't get offsets from rbtz for " + *tzid);
1155 }
1156 if (raw0 != raw1 || dst0 != dst1) {
1157 errln("FAIL: rbtz created by simple rule does not match the original tz for tzid " + *tzid);
1158 }
1159 delete rbtz;
1160 delete tz;
1161 }
1162 }
1163 }
1164
1165 /*
1166 * API coverage tests for TimeZoneRule
1167 */
1168 void
TestTimeZoneRuleCoverage(void)1169 TimeZoneRuleTest::TestTimeZoneRuleCoverage(void) {
1170 UDate time1 = getUTCMillis(2005, UCAL_JULY, 4);
1171 UDate time2 = getUTCMillis(2015, UCAL_JULY, 4);
1172 UDate time3 = getUTCMillis(1950, UCAL_JULY, 4);
1173
1174 DateTimeRule *dtr1 = new DateTimeRule(UCAL_FEBRUARY, 29, UCAL_SUNDAY, FALSE,
1175 3*HOUR, DateTimeRule::WALL_TIME); // Last Sunday on or before Feb 29, at 3 AM, wall time
1176 DateTimeRule *dtr2 = new DateTimeRule(UCAL_MARCH, 11, 2*HOUR,
1177 DateTimeRule::STANDARD_TIME); // Mar 11, at 2 AM, standard time
1178 DateTimeRule *dtr3 = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SATURDAY,
1179 6*HOUR, DateTimeRule::UTC_TIME); //Last Saturday in Oct, at 6 AM, UTC
1180 DateTimeRule *dtr4 = new DateTimeRule(UCAL_MARCH, 8, UCAL_SUNDAY, TRUE,
1181 2*HOUR, DateTimeRule::WALL_TIME); // First Sunday on or after Mar 8, at 2 AM, wall time
1182
1183 AnnualTimeZoneRule *a1 = new AnnualTimeZoneRule("a1", -3*HOUR, 1*HOUR, *dtr1,
1184 2000, AnnualTimeZoneRule::MAX_YEAR);
1185 AnnualTimeZoneRule *a2 = new AnnualTimeZoneRule("a2", -3*HOUR, 1*HOUR, *dtr1,
1186 2000, AnnualTimeZoneRule::MAX_YEAR);
1187 AnnualTimeZoneRule *a3 = new AnnualTimeZoneRule("a3", -3*HOUR, 1*HOUR, *dtr1,
1188 2000, 2010);
1189
1190 InitialTimeZoneRule *i1 = new InitialTimeZoneRule("i1", -3*HOUR, 0);
1191 InitialTimeZoneRule *i2 = new InitialTimeZoneRule("i2", -3*HOUR, 0);
1192 InitialTimeZoneRule *i3 = new InitialTimeZoneRule("i3", -3*HOUR, 1*HOUR);
1193
1194 UDate trtimes1[] = {0.0};
1195 UDate trtimes2[] = {0.0, 10000000.0};
1196
1197 TimeArrayTimeZoneRule *t1 = new TimeArrayTimeZoneRule("t1", -3*HOUR, 0, trtimes1, 1, DateTimeRule::UTC_TIME);
1198 TimeArrayTimeZoneRule *t2 = new TimeArrayTimeZoneRule("t2", -3*HOUR, 0, trtimes1, 1, DateTimeRule::UTC_TIME);
1199 TimeArrayTimeZoneRule *t3 = new TimeArrayTimeZoneRule("t3", -3*HOUR, 0, trtimes2, 2, DateTimeRule::UTC_TIME);
1200 TimeArrayTimeZoneRule *t4 = new TimeArrayTimeZoneRule("t4", -3*HOUR, 0, trtimes1, 1, DateTimeRule::STANDARD_TIME);
1201 TimeArrayTimeZoneRule *t5 = new TimeArrayTimeZoneRule("t5", -4*HOUR, 1*HOUR, trtimes1, 1, DateTimeRule::WALL_TIME);
1202
1203 // DateTimeRule::operator=/clone
1204 DateTimeRule dtr0(UCAL_MAY, 31, 2*HOUR, DateTimeRule::WALL_TIME);
1205 if (dtr0 == *dtr1 || !(dtr0 != *dtr1)) {
1206 errln("FAIL: DateTimeRule dtr0 is not equal to dtr1, but got wrong result");
1207 }
1208 dtr0 = *dtr1;
1209 if (dtr0 != *dtr1 || !(dtr0 == *dtr1)) {
1210 errln("FAIL: DateTimeRule dtr0 is equal to dtr1, but got wrong result");
1211 }
1212 DateTimeRule *dtr0c = dtr0.clone();
1213 if (*dtr0c != *dtr1 || !(*dtr0c == *dtr1)) {
1214 errln("FAIL: DateTimeRule dtr0c is equal to dtr1, but got wrong result");
1215 }
1216 delete dtr0c;
1217
1218 // AnnualTimeZonerule::operator=/clone
1219 AnnualTimeZoneRule a0("a0", 5*HOUR, 1*HOUR, *dtr1, 1990, AnnualTimeZoneRule::MAX_YEAR);
1220 if (a0 == *a1 || !(a0 != *a1)) {
1221 errln("FAIL: AnnualTimeZoneRule a0 is not equal to a1, but got wrong result");
1222 }
1223 a0 = *a1;
1224 if (a0 != *a1 || !(a0 == *a1)) {
1225 errln("FAIL: AnnualTimeZoneRule a0 is equal to a1, but got wrong result");
1226 }
1227 AnnualTimeZoneRule *a0c = a0.clone();
1228 if (*a0c != *a1 || !(*a0c == *a1)) {
1229 errln("FAIL: AnnualTimeZoneRule a0c is equal to a1, but got wrong result");
1230 }
1231 delete a0c;
1232
1233 // AnnualTimeZoneRule::getRule
1234 if (*(a1->getRule()) != *(a2->getRule())) {
1235 errln("FAIL: The same DateTimeRule must be returned from AnnualTimeZoneRule a1 and a2");
1236 }
1237
1238 // AnnualTimeZoneRule::getStartYear
1239 int32_t startYear = a1->getStartYear();
1240 if (startYear != 2000) {
1241 errln((UnicodeString)"FAIL: The start year of AnnualTimeZoneRule a1 must be 2000 - returned: " + startYear);
1242 }
1243
1244 // AnnualTimeZoneRule::getEndYear
1245 int32_t endYear = a1->getEndYear();
1246 if (endYear != AnnualTimeZoneRule::MAX_YEAR) {
1247 errln((UnicodeString)"FAIL: The start year of AnnualTimeZoneRule a1 must be MAX_YEAR - returned: " + endYear);
1248 }
1249 endYear = a3->getEndYear();
1250 if (endYear != 2010) {
1251 errln((UnicodeString)"FAIL: The start year of AnnualTimeZoneRule a3 must be 2010 - returned: " + endYear);
1252 }
1253
1254 // AnnualTimeZone::getStartInYear
1255 UBool b1, b2;
1256 UDate d1, d2;
1257 b1 = a1->getStartInYear(2005, -3*HOUR, 0, d1);
1258 b2 = a3->getStartInYear(2005, -3*HOUR, 0, d2);
1259 if (!b1 || !b2 || d1 != d2) {
1260 errln("FAIL: AnnualTimeZoneRule::getStartInYear did not work as expected");
1261 }
1262 b2 = a3->getStartInYear(2015, -3*HOUR, 0, d2);
1263 if (b2) {
1264 errln("FAIL: AnnualTimeZoneRule::getStartInYear returned TRUE for 2015 which is out of rule range");
1265 }
1266
1267 // AnnualTimeZone::getFirstStart
1268 b1 = a1->getFirstStart(-3*HOUR, 0, d1);
1269 b2 = a1->getFirstStart(-4*HOUR, 1*HOUR, d2);
1270 if (!b1 || !b2 || d1 != d2) {
1271 errln("FAIL: The same start time should be returned by getFirstStart");
1272 }
1273
1274 // AnnualTimeZone::getFinalStart
1275 b1 = a1->getFinalStart(-3*HOUR, 0, d1);
1276 if (b1) {
1277 errln("FAIL: getFinalStart returned TRUE for a1");
1278 }
1279 b1 = a1->getStartInYear(2010, -3*HOUR, 0, d1);
1280 b2 = a3->getFinalStart(-3*HOUR, 0, d2);
1281 if (!b1 || !b2 || d1 != d2) {
1282 errln("FAIL: Bad date is returned by getFinalStart");
1283 }
1284
1285 // AnnualTimeZone::getNextStart / getPreviousStart
1286 b1 = a1->getNextStart(time1, -3*HOUR, 0, FALSE, d1);
1287 if (!b1) {
1288 errln("FAIL: getNextStart returned FALSE for ai");
1289 } else {
1290 b2 = a1->getPreviousStart(d1, -3*HOUR, 0, TRUE, d2);
1291 if (!b2 || d1 != d2) {
1292 errln("FAIL: Bad Date is returned by getPreviousStart");
1293 }
1294 }
1295 b1 = a3->getNextStart(time2, -3*HOUR, 0, FALSE, d1);
1296 if (b1) {
1297 errln("FAIL: getNextStart must return FALSE when no start time is available after the base time");
1298 }
1299 b1 = a3->getFinalStart(-3*HOUR, 0, d1);
1300 b2 = a3->getPreviousStart(time2, -3*HOUR, 0, FALSE, d2);
1301 if (!b1 || !b2 || d1 != d2) {
1302 errln("FAIL: getPreviousStart does not match with getFinalStart after the end year");
1303 }
1304
1305 // AnnualTimeZone::isEquavalentTo
1306 if (!a1->isEquivalentTo(*a2)) {
1307 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to a2, but returned FALSE");
1308 }
1309 if (a1->isEquivalentTo(*a3)) {
1310 errln("FAIL: AnnualTimeZoneRule a1 is not equivalent to a3, but returned TRUE");
1311 }
1312 if (!a1->isEquivalentTo(*a1)) {
1313 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to itself, but returned FALSE");
1314 }
1315 if (a1->isEquivalentTo(*t1)) {
1316 errln("FAIL: AnnualTimeZoneRule is not equivalent to TimeArrayTimeZoneRule, but returned TRUE");
1317 }
1318
1319 // InitialTimezoneRule::operator=/clone
1320 InitialTimeZoneRule i0("i0", 10*HOUR, 0);
1321 if (i0 == *i1 || !(i0 != *i1)) {
1322 errln("FAIL: InitialTimeZoneRule i0 is not equal to i1, but got wrong result");
1323 }
1324 i0 = *i1;
1325 if (i0 != *i1 || !(i0 == *i1)) {
1326 errln("FAIL: InitialTimeZoneRule i0 is equal to i1, but got wrong result");
1327 }
1328 InitialTimeZoneRule *i0c = i0.clone();
1329 if (*i0c != *i1 || !(*i0c == *i1)) {
1330 errln("FAIL: InitialTimeZoneRule i0c is equal to i1, but got wrong result");
1331 }
1332 delete i0c;
1333
1334 // InitialTimeZoneRule::isEquivalentRule
1335 if (!i1->isEquivalentTo(*i2)) {
1336 errln("FAIL: InitialTimeZoneRule i1 is equivalent to i2, but returned FALSE");
1337 }
1338 if (i1->isEquivalentTo(*i3)) {
1339 errln("FAIL: InitialTimeZoneRule i1 is not equivalent to i3, but returned TRUE");
1340 }
1341 if (i1->isEquivalentTo(*a1)) {
1342 errln("FAIL: An InitialTimeZoneRule is not equivalent to an AnnualTimeZoneRule, but returned TRUE");
1343 }
1344
1345 // InitialTimeZoneRule::getFirstStart/getFinalStart/getNextStart/getPreviousStart
1346 b1 = i1->getFirstStart(0, 0, d1);
1347 if (b1) {
1348 errln("FAIL: InitialTimeZone::getFirstStart returned TRUE");
1349 }
1350 b1 = i1->getFinalStart(0, 0, d1);
1351 if (b1) {
1352 errln("FAIL: InitialTimeZone::getFinalStart returned TRUE");
1353 }
1354 b1 = i1->getNextStart(time1, 0, 0, FALSE, d1);
1355 if (b1) {
1356 errln("FAIL: InitialTimeZone::getNextStart returned TRUE");
1357 }
1358 b1 = i1->getPreviousStart(time1, 0, 0, FALSE, d1);
1359 if (b1) {
1360 errln("FAIL: InitialTimeZone::getPreviousStart returned TRUE");
1361 }
1362
1363 // TimeArrayTimeZoneRule::operator=/clone
1364 TimeArrayTimeZoneRule t0("t0", 4*HOUR, 0, trtimes1, 1, DateTimeRule::UTC_TIME);
1365 if (t0 == *t1 || !(t0 != *t1)) {
1366 errln("FAIL: TimeArrayTimeZoneRule t0 is not equal to t1, but got wrong result");
1367 }
1368 t0 = *t1;
1369 if (t0 != *t1 || !(t0 == *t1)) {
1370 errln("FAIL: TimeArrayTimeZoneRule t0 is equal to t1, but got wrong result");
1371 }
1372 TimeArrayTimeZoneRule *t0c = t0.clone();
1373 if (*t0c != *t1 || !(*t0c == *t1)) {
1374 errln("FAIL: TimeArrayTimeZoneRule t0c is equal to t1, but got wrong result");
1375 }
1376 delete t0c;
1377
1378 // TimeArrayTimeZoneRule::countStartTimes
1379 if (t1->countStartTimes() != 1) {
1380 errln("FAIL: Bad start time count is returned by TimeArrayTimeZoneRule::countStartTimes");
1381 }
1382
1383 // TimeArrayTimeZoneRule::getStartTimeAt
1384 b1 = t1->getStartTimeAt(-1, d1);
1385 if (b1) {
1386 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned TRUE for index -1");
1387 }
1388 b1 = t1->getStartTimeAt(0, d1);
1389 if (!b1 || d1 != trtimes1[0]) {
1390 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned incorrect result for index 0");
1391 }
1392 b1 = t1->getStartTimeAt(1, d1);
1393 if (b1) {
1394 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned TRUE for index 1");
1395 }
1396
1397 // TimeArrayTimeZoneRule::getTimeType
1398 if (t1->getTimeType() != DateTimeRule::UTC_TIME) {
1399 errln("FAIL: TimeArrayTimeZoneRule t1 uses UTC_TIME, but different type is returned");
1400 }
1401 if (t4->getTimeType() != DateTimeRule::STANDARD_TIME) {
1402 errln("FAIL: TimeArrayTimeZoneRule t4 uses STANDARD_TIME, but different type is returned");
1403 }
1404 if (t5->getTimeType() != DateTimeRule::WALL_TIME) {
1405 errln("FAIL: TimeArrayTimeZoneRule t5 uses WALL_TIME, but different type is returned");
1406 }
1407
1408 // TimeArrayTimeZoneRule::getFirstStart/getFinalStart
1409 b1 = t1->getFirstStart(0, 0, d1);
1410 if (!b1 || d1 != trtimes1[0]) {
1411 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t1");
1412 }
1413 b1 = t1->getFinalStart(0, 0, d1);
1414 if (!b1 || d1 != trtimes1[0]) {
1415 errln("FAIL: Bad final start time returned from TimeArrayTimeZoneRule t1");
1416 }
1417 b1 = t4->getFirstStart(-4*HOUR, 1*HOUR, d1);
1418 if (!b1 || d1 != (trtimes1[0] + 4*HOUR)) {
1419 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t4");
1420 }
1421 b1 = t5->getFirstStart(-4*HOUR, 1*HOUR, d1);
1422 if (!b1 || d1 != (trtimes1[0] + 3*HOUR)) {
1423 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t5");
1424 }
1425
1426 // TimeArrayTimeZoneRule::getNextStart/getPreviousStart
1427 b1 = t3->getNextStart(time1, -3*HOUR, 1*HOUR, FALSE, d1);
1428 if (b1) {
1429 errln("FAIL: getNextStart returned TRUE after the final transition for t3");
1430 }
1431 b1 = t3->getPreviousStart(time1, -3*HOUR, 1*HOUR, FALSE, d1);
1432 if (!b1 || d1 != trtimes2[1]) {
1433 errln("FAIL: Bad start time returned by getPreviousStart for t3");
1434 } else {
1435 b2 = t3->getPreviousStart(d1, -3*HOUR, 1*HOUR, FALSE, d2);
1436 if (!b2 || d2 != trtimes2[0]) {
1437 errln("FAIL: Bad start time returned by getPreviousStart for t3");
1438 }
1439 }
1440 b1 = t3->getPreviousStart(time3, -3*HOUR, 1*HOUR, FALSE, d1); //time3 - year 1950, no result expected
1441 if (b1) {
1442 errln("FAIL: getPreviousStart returned TRUE before the first transition for t3");
1443 }
1444
1445 // TimeArrayTimeZoneRule::isEquivalentTo
1446 if (!t1->isEquivalentTo(*t2)) {
1447 errln("FAIL: TimeArrayTimeZoneRule t1 is equivalent to t2, but returned FALSE");
1448 }
1449 if (t1->isEquivalentTo(*t3)) {
1450 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t3, but returned TRUE");
1451 }
1452 if (t1->isEquivalentTo(*t4)) {
1453 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t4, but returned TRUE");
1454 }
1455 if (t1->isEquivalentTo(*a1)) {
1456 errln("FAIL: TimeArrayTimeZoneRule is not equivalent to AnnualTimeZoneRule, but returned TRUE");
1457 }
1458
1459 delete dtr1;
1460 delete dtr2;
1461 delete dtr3;
1462 delete dtr4;
1463 delete a1;
1464 delete a2;
1465 delete a3;
1466 delete i1;
1467 delete i2;
1468 delete i3;
1469 delete t1;
1470 delete t2;
1471 delete t3;
1472 delete t4;
1473 delete t5;
1474 }
1475
1476 /*
1477 * API coverage test for BasicTimeZone APIs in SimpleTimeZone
1478 */
1479 void
TestSimpleTimeZoneCoverage(void)1480 TimeZoneRuleTest::TestSimpleTimeZoneCoverage(void) {
1481 UDate time1 = getUTCMillis(1990, UCAL_JUNE, 1);
1482 UDate time2 = getUTCMillis(2000, UCAL_JUNE, 1);
1483
1484 TimeZoneTransition tzt1, tzt2;
1485 UBool avail1, avail2;
1486 UErrorCode status = U_ZERO_ERROR;
1487 const TimeZoneRule *trrules[2];
1488 const InitialTimeZoneRule *ir = NULL;
1489 int32_t numTzRules;
1490
1491 // BasicTimeZone API implementation in SimpleTimeZone
1492 SimpleTimeZone *stz1 = new SimpleTimeZone(-5*HOUR, "GMT-5");
1493
1494 avail1 = stz1->getNextTransition(time1, FALSE, tzt1);
1495 if (avail1) {
1496 errln("FAIL: No transition must be returned by getNextTranstion for SimpleTimeZone with no DST rule");
1497 }
1498 avail1 = stz1->getPreviousTransition(time1, FALSE, tzt1);
1499 if (avail1) {
1500 errln("FAIL: No transition must be returned by getPreviousTransition for SimpleTimeZone with no DST rule");
1501 }
1502
1503 numTzRules = stz1->countTransitionRules(status);
1504 if (U_FAILURE(status)) {
1505 errln("FAIL: countTransitionRules failed");
1506 }
1507 if (numTzRules != 0) {
1508 errln((UnicodeString)"FAIL: countTransitionRules returned " + numTzRules);
1509 }
1510 numTzRules = 2;
1511 stz1->getTimeZoneRules(ir, trrules, numTzRules, status);
1512 if (U_FAILURE(status)) {
1513 errln("FAIL: getTimeZoneRules failed");
1514 }
1515 if (numTzRules != 0) {
1516 errln("FAIL: Incorrect transition rule count");
1517 }
1518 if (ir == NULL || ir->getRawOffset() != stz1->getRawOffset()) {
1519 errln("FAIL: Bad initial time zone rule");
1520 }
1521
1522 // Set DST rule
1523 stz1->setStartRule(UCAL_MARCH, 11, 2*HOUR, status); // March 11
1524 stz1->setEndRule(UCAL_NOVEMBER, 1, UCAL_SUNDAY, 2*HOUR, status); // First Sunday in November
1525 if (U_FAILURE(status)) {
1526 errln("FAIL: Failed to set DST rules in a SimpleTimeZone");
1527 }
1528
1529 avail1 = stz1->getNextTransition(time1, FALSE, tzt1);
1530 if (!avail1) {
1531 errln("FAIL: Non-null transition must be returned by getNextTranstion for SimpleTimeZone with a DST rule");
1532 }
1533 avail1 = stz1->getPreviousTransition(time1, FALSE, tzt1);
1534 if (!avail1) {
1535 errln("FAIL: Non-null transition must be returned by getPreviousTransition for SimpleTimeZone with a DST rule");
1536 }
1537
1538 numTzRules = stz1->countTransitionRules(status);
1539 if (U_FAILURE(status)) {
1540 errln("FAIL: countTransitionRules failed");
1541 }
1542 if (numTzRules != 2) {
1543 errln((UnicodeString)"FAIL: countTransitionRules returned " + numTzRules);
1544 }
1545
1546 numTzRules = 2;
1547 trrules[0] = NULL;
1548 trrules[1] = NULL;
1549 stz1->getTimeZoneRules(ir, trrules, numTzRules, status);
1550 if (U_FAILURE(status)) {
1551 errln("FAIL: getTimeZoneRules failed");
1552 }
1553 if (numTzRules != 2) {
1554 errln("FAIL: Incorrect transition rule count");
1555 }
1556 if (ir == NULL || ir->getRawOffset() != stz1->getRawOffset()) {
1557 errln("FAIL: Bad initial time zone rule");
1558 }
1559 if (trrules[0] == NULL || trrules[0]->getRawOffset() != stz1->getRawOffset()) {
1560 errln("FAIL: Bad transition rule 0");
1561 }
1562 if (trrules[1] == NULL || trrules[1]->getRawOffset() != stz1->getRawOffset()) {
1563 errln("FAIL: Bad transition rule 1");
1564 }
1565
1566 // Set DST start year
1567 stz1->setStartYear(2007);
1568 avail1 = stz1->getPreviousTransition(time1, FALSE, tzt1);
1569 if (avail1) {
1570 errln("FAIL: No transition must be returned before 1990");
1571 }
1572 avail1 = stz1->getNextTransition(time1, FALSE, tzt1); // transition after 1990-06-01
1573 avail2 = stz1->getNextTransition(time2, FALSE, tzt2); // transition after 2000-06-01
1574 if (!avail1 || !avail2 || tzt1 != tzt2) {
1575 errln("FAIL: Bad transition returned by SimpleTimeZone::getNextTransition");
1576 }
1577 delete stz1;
1578 }
1579
1580 /*
1581 * API coverage test for VTimeZone
1582 */
1583 void
TestVTimeZoneCoverage(void)1584 TimeZoneRuleTest::TestVTimeZoneCoverage(void) {
1585 UErrorCode status = U_ZERO_ERROR;
1586 UnicodeString TZID("Europe/Moscow");
1587
1588 BasicTimeZone *otz = (BasicTimeZone*)TimeZone::createTimeZone(TZID);
1589 VTimeZone *vtz = VTimeZone::createVTimeZoneByID(TZID);
1590
1591 // getOffset(era, year, month, day, dayOfWeek, milliseconds, ec)
1592 int32_t offset1 = otz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, status);
1593 if (U_FAILURE(status)) {
1594 errln("FAIL: getOffset(7 args) failed for otz");
1595 }
1596 int32_t offset2 = vtz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, status);
1597 if (U_FAILURE(status)) {
1598 errln("FAIL: getOffset(7 args) failed for vtz");
1599 }
1600 if (offset1 != offset2) {
1601 errln("FAIL: getOffset(7 args) returned different results in VTimeZone and OlsonTimeZone");
1602 }
1603
1604 // getOffset(era, year, month, day, dayOfWeek, milliseconds, monthLength, ec)
1605 offset1 = otz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, 31, status);
1606 if (U_FAILURE(status)) {
1607 errln("FAIL: getOffset(8 args) failed for otz");
1608 }
1609 offset2 = vtz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, 31, status);
1610 if (U_FAILURE(status)) {
1611 errln("FAIL: getOffset(8 args) failed for vtz");
1612 }
1613 if (offset1 != offset2) {
1614 errln("FAIL: getOffset(8 args) returned different results in VTimeZone and OlsonTimeZone");
1615 }
1616
1617
1618 // getOffset(date, local, rawOffset, dstOffset, ec)
1619 UDate t = Calendar::getNow();
1620 int32_t rawOffset1, dstSavings1;
1621 int32_t rawOffset2, dstSavings2;
1622
1623 otz->getOffset(t, FALSE, rawOffset1, dstSavings1, status);
1624 if (U_FAILURE(status)) {
1625 errln("FAIL: getOffset(5 args) failed for otz");
1626 }
1627 vtz->getOffset(t, FALSE, rawOffset2, dstSavings2, status);
1628 if (U_FAILURE(status)) {
1629 errln("FAIL: getOffset(5 args) failed for vtz");
1630 }
1631 if (rawOffset1 != rawOffset2 || dstSavings1 != dstSavings2) {
1632 errln("FAIL: getOffset(long,boolean,int[]) returned different results in VTimeZone and OlsonTimeZone");
1633 }
1634
1635 // getRawOffset
1636 if (otz->getRawOffset() != vtz->getRawOffset()) {
1637 errln("FAIL: getRawOffset returned different results in VTimeZone and OlsonTimeZone");
1638 }
1639
1640 // inDaylightTime
1641 UBool inDst1, inDst2;
1642 inDst1 = otz->inDaylightTime(t, status);
1643 if (U_FAILURE(status)) {
1644 errln("FAIL: inDaylightTime failed for otz");
1645 }
1646 inDst2 = vtz->inDaylightTime(t, status);
1647 if (U_FAILURE(status)) {
1648 errln("FAIL: inDaylightTime failed for vtz");
1649 }
1650 if (inDst1 != inDst2) {
1651 errln("FAIL: inDaylightTime returned different results in VTimeZone and OlsonTimeZone");
1652 }
1653
1654 // useDaylightTime
1655 if (otz->useDaylightTime() != vtz->useDaylightTime()) {
1656 errln("FAIL: useDaylightTime returned different results in VTimeZone and OlsonTimeZone");
1657 }
1658
1659 // setRawOffset
1660 const int32_t RAW = -10*HOUR;
1661 VTimeZone *tmpvtz = (VTimeZone*)vtz->clone();
1662 tmpvtz->setRawOffset(RAW);
1663 if (tmpvtz->getRawOffset() != RAW) {
1664 logln("setRawOffset is implemented in VTimeZone");
1665 }
1666
1667 // hasSameRules
1668 UBool bSame = otz->hasSameRules(*vtz);
1669 logln((UnicodeString)"OlsonTimeZone::hasSameRules(VTimeZone) should return FALSE always for now - actual: " + bSame);
1670
1671 // getTZURL/setTZURL
1672 UnicodeString TZURL("http://icu-project.org/timezone");
1673 UnicodeString url;
1674 if (vtz->getTZURL(url)) {
1675 errln("FAIL: getTZURL returned TRUE");
1676 }
1677 vtz->setTZURL(TZURL);
1678 if (!vtz->getTZURL(url) || url != TZURL) {
1679 errln("FAIL: URL returned by getTZURL does not match the one set by setTZURL");
1680 }
1681
1682 // getLastModified/setLastModified
1683 UDate lastmod;
1684 if (vtz->getLastModified(lastmod)) {
1685 errln("FAIL: getLastModified returned TRUE");
1686 }
1687 vtz->setLastModified(t);
1688 if (!vtz->getLastModified(lastmod) || lastmod != t) {
1689 errln("FAIL: Date returned by getLastModified does not match the one set by setLastModified");
1690 }
1691
1692 // getNextTransition/getPreviousTransition
1693 UDate base = getUTCMillis(2007, UCAL_JULY, 1);
1694 TimeZoneTransition tzt1, tzt2;
1695 UBool btr1 = otz->getNextTransition(base, TRUE, tzt1);
1696 UBool btr2 = vtz->getNextTransition(base, TRUE, tzt2);
1697 if (!btr1 || !btr2 || tzt1 != tzt2) {
1698 errln("FAIL: getNextTransition returned different results in VTimeZone and OlsonTimeZone");
1699 }
1700 btr1 = otz->getPreviousTransition(base, FALSE, tzt1);
1701 btr2 = vtz->getPreviousTransition(base, FALSE, tzt2);
1702 if (!btr1 || !btr2 || tzt1 != tzt2) {
1703 errln("FAIL: getPreviousTransition returned different results in VTimeZone and OlsonTimeZone");
1704 }
1705
1706 // TimeZoneTransition constructor/clone
1707 TimeZoneTransition *tzt1c = tzt1.clone();
1708 if (*tzt1c != tzt1 || !(*tzt1c == tzt1)) {
1709 errln("FAIL: TimeZoneTransition tzt1c is equal to tzt1, but got wrong result");
1710 }
1711 delete tzt1c;
1712 TimeZoneTransition tzt3(tzt1);
1713 if (tzt3 != tzt1 || !(tzt3 == tzt1)) {
1714 errln("FAIL: TimeZoneTransition tzt3 is equal to tzt1, but got wrong result");
1715 }
1716
1717 // hasEquivalentTransitions
1718 UDate time1 = getUTCMillis(1950, UCAL_JANUARY, 1);
1719 UDate time2 = getUTCMillis(2020, UCAL_JANUARY, 1);
1720 UBool equiv = vtz->hasEquivalentTransitions(*otz, time1, time2, FALSE, status);
1721 if (U_FAILURE(status)) {
1722 errln("FAIL: hasEquivalentTransitions failed for vtz/otz");
1723 }
1724 if (!equiv) {
1725 errln("FAIL: hasEquivalentTransitons returned false for the same time zone");
1726 }
1727
1728 // operator=/operator==/operator!=
1729 VTimeZone *vtz1 = VTimeZone::createVTimeZoneByID("America/Los_Angeles");
1730 if (*vtz1 == *vtz || !(*vtz1 != *vtz)) {
1731 errln("FAIL: VTimeZone vtz1 is not equal to vtz, but got wrong result");
1732 }
1733 *vtz1 = *vtz;
1734 if (*vtz1 != *vtz || !(*vtz1 == *vtz)) {
1735 errln("FAIL: VTimeZone vtz1 is equal to vtz, but got wrong result");
1736 }
1737
1738 delete otz;
1739 delete vtz;
1740 delete tmpvtz;
1741 delete vtz1;
1742 }
1743
1744
1745 void
TestVTimeZoneParse(void)1746 TimeZoneRuleTest::TestVTimeZoneParse(void) {
1747 UErrorCode status = U_ZERO_ERROR;
1748
1749 // Trying to create VTimeZone from empty data
1750 UnicodeString emptyData;
1751 VTimeZone *empty = VTimeZone::createVTimeZone(emptyData, status);
1752 if (U_SUCCESS(status) || empty != NULL) {
1753 delete empty;
1754 errln("FAIL: Non-null VTimeZone is returned for empty VTIMEZONE data");
1755 }
1756 status = U_ZERO_ERROR;
1757
1758 // Create VTimeZone for Asia/Tokyo
1759 UnicodeString asiaTokyoID("Asia/Tokyo");
1760 static const UChar asiaTokyo[] = {
1761 /* "BEGIN:VTIMEZONE\x0D\x0A" */
1762 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
1763 /* "TZID:Asia\x0D\x0A" */
1764 0x54,0x5A,0x49,0x44,0x3A,0x41,0x73,0x69,0x61,0x0D,0x0A,
1765 /* "\x09/Tokyo\x0D\x0A" */
1766 0x09,0x2F,0x54,0x6F,0x6B,0x79,0x6F,0x0D,0x0A,
1767 /* "BEGIN:STANDARD\x0D\x0A" */
1768 0x42,0x45,0x47,0x49,0x4E,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1769 /* "TZOFFSETFROM:+0900\x0D\x0A" */
1770 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2B,0x30,0x39,0x30,0x30,0x0D,0x0A,
1771 /* "TZOFFSETTO:+0900\x0D\x0A" */
1772 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2B,0x30,0x39,0x30,0x30,0x0D,0x0A,
1773 /* "TZNAME:JST\x0D\x0A" */
1774 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x4A,0x53,0x54,0x0D,0x0A,
1775 /* "DTSTART:19700101\x0D\x0A" */
1776 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3A,0x31,0x39,0x37,0x30,0x30,0x31,0x30,0x31,0x0D,0x0A,
1777 /* " T000000\x0D\x0A" */
1778 0x20,0x54,0x30,0x30,0x30,0x30,0x30,0x30,0x0D,0x0A,
1779 /* "END:STANDARD\x0D\x0A" */
1780 0x45,0x4E,0x44,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1781 /* "END:VTIMEZONE" */
1782 0x45,0x4E,0x44,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,
1783 0
1784 };
1785 VTimeZone *tokyo = VTimeZone::createVTimeZone(asiaTokyo, status);
1786 if (U_FAILURE(status) || tokyo == NULL) {
1787 errln("FAIL: Failed to create a VTimeZone tokyo");
1788 } else {
1789 // Check ID
1790 UnicodeString tzid;
1791 tokyo->getID(tzid);
1792 if (tzid != asiaTokyoID) {
1793 errln((UnicodeString)"FAIL: Invalid TZID: " + tzid);
1794 }
1795 // Make sure offsets are correct
1796 int32_t rawOffset, dstSavings;
1797 tokyo->getOffset(Calendar::getNow(), FALSE, rawOffset, dstSavings, status);
1798 if (U_FAILURE(status)) {
1799 errln("FAIL: getOffset failed for tokyo");
1800 }
1801 if (rawOffset != 9*HOUR || dstSavings != 0) {
1802 errln("FAIL: Bad offsets returned by a VTimeZone created for Tokyo");
1803 }
1804 }
1805 delete tokyo;
1806
1807 // Create VTimeZone from VTIMEZONE data
1808 static const UChar fooData[] = {
1809 /* "BEGIN:VCALENDAR\x0D\x0A" */
1810 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x43,0x41,0x4C,0x45,0x4E,0x44,0x41,0x52,0x0D,0x0A,
1811 /* "BEGIN:VTIMEZONE\x0D\x0A" */
1812 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
1813 /* "TZID:FOO\x0D\x0A" */
1814 0x54,0x5A,0x49,0x44,0x3A,0x46,0x4F,0x4F,0x0D,0x0A,
1815 /* "BEGIN:STANDARD\x0D\x0A" */
1816 0x42,0x45,0x47,0x49,0x4E,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1817 /* "TZOFFSETFROM:-0700\x0D\x0A" */
1818 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2D,0x30,0x37,0x30,0x30,0x0D,0x0A,
1819 /* "TZOFFSETTO:-0800\x0D\x0A" */
1820 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2D,0x30,0x38,0x30,0x30,0x0D,0x0A,
1821 /* "TZNAME:FST\x0D\x0A" */
1822 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x46,0x53,0x54,0x0D,0x0A,
1823 /* "DTSTART:20071010T010000\x0D\x0A" */
1824 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3A,0x32,0x30,0x30,0x37,0x31,0x30,0x31,0x30,0x54,0x30,0x31,0x30,0x30,0x30,0x30,0x0D,0x0A,
1825 /* "RRULE:FREQ=YEARLY;BYDAY=WE;BYMONTHDAY=10,11,12,13,14,15,16;BYMONTH=10\x0D\x0A" */
1826 0x52,0x52,0x55,0x4C,0x45,0x3A,0x46,0x52,0x45,0x51,0x3D,0x59,0x45,0x41,0x52,0x4C,0x59,0x3B,0x42,0x59,0x44,0x41,0x59,0x3D,0x57,0x45,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x44,0x41,0x59,0x3D,0x31,0x30,0x2C,0x31,0x31,0x2C,0x31,0x32,0x2C,0x31,0x33,0x2C,0x31,0x34,0x2C,0x31,0x35,0x2C,0x31,0x36,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x3D,0x31,0x30,0x0D,0x0A,
1827 /* "END:STANDARD\x0D\x0A" */
1828 0x45,0x4E,0x44,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1829 /* "BEGIN:DAYLIGHT\x0D\x0A" */
1830 0x42,0x45,0x47,0x49,0x4E,0x3A,0x44,0x41,0x59,0x4C,0x49,0x47,0x48,0x54,0x0D,0x0A,
1831 /* "TZOFFSETFROM:-0800\x0D\x0A" */
1832 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2D,0x30,0x38,0x30,0x30,0x0D,0x0A,
1833 /* "TZOFFSETTO:-0700\x0D\x0A" */
1834 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2D,0x30,0x37,0x30,0x30,0x0D,0x0A,
1835 /* "TZNAME:FDT\x0D\x0A" */
1836 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x46,0x44,0x54,0x0D,0x0A,
1837 /* "DTSTART:20070415T010000\x0D\x0A" */
1838 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3A,0x32,0x30,0x30,0x37,0x30,0x34,0x31,0x35,0x54,0x30,0x31,0x30,0x30,0x30,0x30,0x0D,0x0A,
1839 /* "RRULE:FREQ=YEARLY;BYMONTHDAY=15;BYMONTH=4\x0D\x0A" */
1840 0x52,0x52,0x55,0x4C,0x45,0x3A,0x46,0x52,0x45,0x51,0x3D,0x59,0x45,0x41,0x52,0x4C,0x59,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x44,0x41,0x59,0x3D,0x31,0x35,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x3D,0x34,0x0D,0x0A,
1841 /* "END:DAYLIGHT\x0D\x0A" */
1842 0x45,0x4E,0x44,0x3A,0x44,0x41,0x59,0x4C,0x49,0x47,0x48,0x54,0x0D,0x0A,
1843 /* "END:VTIMEZONE\x0D\x0A" */
1844 0x45,0x4E,0x44,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
1845 /* "END:VCALENDAR" */
1846 0x45,0x4E,0x44,0x3A,0x56,0x43,0x41,0x4C,0x45,0x4E,0x44,0x41,0x52,
1847 0
1848 };
1849
1850 VTimeZone *foo = VTimeZone::createVTimeZone(fooData, status);
1851 if (U_FAILURE(status) || foo == NULL) {
1852 errln("FAIL: Failed to create a VTimeZone foo");
1853 } else {
1854 // Write VTIMEZONE data
1855 UnicodeString fooData2;
1856 foo->write(getUTCMillis(2005, UCAL_JANUARY, 1), fooData2, status);
1857 if (U_FAILURE(status)) {
1858 errln("FAIL: Failed to write VTIMEZONE data for foo");
1859 }
1860 logln(fooData2);
1861 }
1862 delete foo;
1863 }
1864
1865 //----------- private test helpers -------------------------------------------------
1866
1867 UDate
getUTCMillis(int32_t y,int32_t m,int32_t d,int32_t hr,int32_t min,int32_t sec,int32_t msec)1868 TimeZoneRuleTest::getUTCMillis(int32_t y, int32_t m, int32_t d,
1869 int32_t hr, int32_t min, int32_t sec, int32_t msec) {
1870 UErrorCode status = U_ZERO_ERROR;
1871 const TimeZone *tz = TimeZone::getGMT();
1872 Calendar *cal = Calendar::createInstance(*tz, status);
1873 if (U_FAILURE(status)) {
1874 delete cal;
1875 errln("FAIL: Calendar::createInstance failed");
1876 return 0.0;
1877 }
1878 cal->set(y, m, d, hr, min, sec);
1879 cal->set(UCAL_MILLISECOND, msec);
1880 UDate utc = cal->getTime(status);
1881 if (U_FAILURE(status)) {
1882 delete cal;
1883 errln("FAIL: Calendar::getTime failed");
1884 return 0.0;
1885 }
1886 delete cal;
1887 return utc;
1888 }
1889
1890 /*
1891 * Check if a time shift really happens on each transition returned by getNextTransition or
1892 * getPreviousTransition in the specified time range
1893 */
1894 void
verifyTransitions(BasicTimeZone & icutz,UDate start,UDate end)1895 TimeZoneRuleTest::verifyTransitions(BasicTimeZone& icutz, UDate start, UDate end) {
1896 UErrorCode status = U_ZERO_ERROR;
1897 UDate time;
1898 int32_t raw, dst, raw0, dst0;
1899 TimeZoneTransition tzt, tzt0;
1900 UBool avail;
1901 UBool first = TRUE;
1902 UnicodeString tzid;
1903
1904 // Ascending
1905 time = start;
1906 while (TRUE) {
1907 avail = icutz.getNextTransition(time, FALSE, tzt);
1908 if (!avail) {
1909 break;
1910 }
1911 time = tzt.getTime();
1912 if (time >= end) {
1913 break;
1914 }
1915 icutz.getOffset(time, FALSE, raw, dst, status);
1916 icutz.getOffset(time - 1, FALSE, raw0, dst0, status);
1917 if (U_FAILURE(status)) {
1918 errln("FAIL: Error in getOffset");
1919 break;
1920 }
1921
1922 if (raw == raw0 && dst == dst0) {
1923 errln((UnicodeString)"FAIL: False transition returned by getNextTransition for "
1924 + icutz.getID(tzid) + " at " + dateToString(time));
1925 }
1926 if (!first &&
1927 (tzt0.getTo()->getRawOffset() != tzt.getFrom()->getRawOffset()
1928 || tzt0.getTo()->getDSTSavings() != tzt.getFrom()->getDSTSavings())) {
1929 errln((UnicodeString)"FAIL: TO rule of the previous transition does not match FROM rule of this transtion at "
1930 + dateToString(time) + " for " + icutz.getID(tzid));
1931 }
1932 tzt0 = tzt;
1933 first = FALSE;
1934 }
1935
1936 // Descending
1937 first = TRUE;
1938 time = end;
1939 while(true) {
1940 avail = icutz.getPreviousTransition(time, FALSE, tzt);
1941 if (!avail) {
1942 break;
1943 }
1944 time = tzt.getTime();
1945 if (time <= start) {
1946 break;
1947 }
1948 icutz.getOffset(time, FALSE, raw, dst, status);
1949 icutz.getOffset(time - 1, FALSE, raw0, dst0, status);
1950 if (U_FAILURE(status)) {
1951 errln("FAIL: Error in getOffset");
1952 break;
1953 }
1954
1955 if (raw == raw0 && dst == dst0) {
1956 errln((UnicodeString)"FAIL: False transition returned by getPreviousTransition for "
1957 + icutz.getID(tzid) + " at " + dateToString(time));
1958 }
1959
1960 if (!first &&
1961 (tzt0.getFrom()->getRawOffset() != tzt.getTo()->getRawOffset()
1962 || tzt0.getFrom()->getDSTSavings() != tzt.getTo()->getDSTSavings())) {
1963 errln((UnicodeString)"FAIL: TO rule of the next transition does not match FROM rule in this transtion at "
1964 + dateToString(time) + " for " + icutz.getID(tzid));
1965 }
1966 tzt0 = tzt;
1967 first = FALSE;
1968 }
1969 }
1970
1971 /*
1972 * Compare all time transitions in 2 time zones in the specified time range in ascending order
1973 */
1974 void
compareTransitionsAscending(BasicTimeZone & z1,BasicTimeZone & z2,UDate start,UDate end,UBool inclusive)1975 TimeZoneRuleTest::compareTransitionsAscending(BasicTimeZone& z1, BasicTimeZone& z2,
1976 UDate start, UDate end, UBool inclusive) {
1977 UnicodeString zid1, zid2;
1978 TimeZoneTransition tzt1, tzt2;
1979 UBool avail1, avail2;
1980 UBool inRange1, inRange2;
1981
1982 z1.getID(zid1);
1983 z2.getID(zid2);
1984
1985 UDate time = start;
1986 while (TRUE) {
1987 avail1 = z1.getNextTransition(time, inclusive, tzt1);
1988 avail2 = z2.getNextTransition(time, inclusive, tzt2);
1989
1990 inRange1 = inRange2 = FALSE;
1991 if (avail1) {
1992 if (tzt1.getTime() < end || (inclusive && tzt1.getTime() == end)) {
1993 inRange1 = TRUE;
1994 }
1995 }
1996 if (avail2) {
1997 if (tzt2.getTime() < end || (inclusive && tzt2.getTime() == end)) {
1998 inRange2 = TRUE;
1999 }
2000 }
2001 if (!inRange1 && !inRange2) {
2002 // No more transition in the range
2003 break;
2004 }
2005 if (!inRange1) {
2006 errln((UnicodeString)"FAIL: " + zid1 + " does not have any transitions after "
2007 + dateToString(time) + " before " + dateToString(end));
2008 break;
2009 }
2010 if (!inRange2) {
2011 errln((UnicodeString)"FAIL: " + zid2 + " does not have any transitions after "
2012 + dateToString(time) + " before " + dateToString(end));
2013 break;
2014 }
2015 if (tzt1.getTime() != tzt2.getTime()) {
2016 errln((UnicodeString)"FAIL: First transition after " + dateToString(time) + " "
2017 + zid1 + "[" + dateToString(tzt1.getTime()) + "] "
2018 + zid2 + "[" + dateToString(tzt2.getTime()) + "]");
2019 break;
2020 }
2021 time = tzt1.getTime();
2022 if (inclusive) {
2023 time += 1;
2024 }
2025 }
2026 }
2027
2028 /*
2029 * Compare all time transitions in 2 time zones in the specified time range in descending order
2030 */
2031 void
compareTransitionsDescending(BasicTimeZone & z1,BasicTimeZone & z2,UDate start,UDate end,UBool inclusive)2032 TimeZoneRuleTest::compareTransitionsDescending(BasicTimeZone& z1, BasicTimeZone& z2,
2033 UDate start, UDate end, UBool inclusive) {
2034 UnicodeString zid1, zid2;
2035 TimeZoneTransition tzt1, tzt2;
2036 UBool avail1, avail2;
2037 UBool inRange1, inRange2;
2038
2039 z1.getID(zid1);
2040 z2.getID(zid2);
2041
2042 UDate time = end;
2043 while (TRUE) {
2044 avail1 = z1.getPreviousTransition(time, inclusive, tzt1);
2045 avail2 = z2.getPreviousTransition(time, inclusive, tzt2);
2046
2047 inRange1 = inRange2 = FALSE;
2048 if (avail1) {
2049 if (tzt1.getTime() > start || (inclusive && tzt1.getTime() == start)) {
2050 inRange1 = TRUE;
2051 }
2052 }
2053 if (avail2) {
2054 if (tzt2.getTime() > start || (inclusive && tzt2.getTime() == start)) {
2055 inRange2 = TRUE;
2056 }
2057 }
2058 if (!inRange1 && !inRange2) {
2059 // No more transition in the range
2060 break;
2061 }
2062 if (!inRange1) {
2063 errln((UnicodeString)"FAIL: " + zid1 + " does not have any transitions before "
2064 + dateToString(time) + " after " + dateToString(start));
2065 break;
2066 }
2067 if (!inRange2) {
2068 errln((UnicodeString)"FAIL: " + zid2 + " does not have any transitions before "
2069 + dateToString(time) + " after " + dateToString(start));
2070 break;
2071 }
2072 if (tzt1.getTime() != tzt2.getTime()) {
2073 errln((UnicodeString)"FAIL: Last transition before " + dateToString(time) + " "
2074 + zid1 + "[" + dateToString(tzt1.getTime()) + "] "
2075 + zid2 + "[" + dateToString(tzt2.getTime()) + "]");
2076 break;
2077 }
2078 time = tzt1.getTime();
2079 if (inclusive) {
2080 time -= 1;
2081 }
2082 }
2083 }
2084
2085 #endif /* #if !UCONFIG_NO_FORMATTING */
2086
2087 //eof
2088