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