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