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