2 *******************************************************************************
3 * Copyright (C) 2007-2012, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
8 #include "unicode/utypes.h"
10 #if !UCONFIG_NO_FORMATTING
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"
30 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
31 #define HOUR (60*60*1000)
33 static const UVersionInfo ICU_453
= {4,5,3,0};
35 static const char *const TESTZIDS
[] = {
38 "America/Los_Angeles",
39 "America/Indiana/Indianapolis",
51 static UBool
hasEquivalentTransitions(/*const*/ BasicTimeZone
& tz1
, /*const*/BasicTimeZone
& tz2
,
52 UDate start
, UDate end
,
53 UBool ignoreDstAmount
, int32_t maxTransitionTimeDelta
,
56 class TestZIDEnumeration
: public StringEnumeration
{
58 TestZIDEnumeration(UBool all
= FALSE
);
59 ~TestZIDEnumeration();
61 virtual int32_t count(UErrorCode
& /*status*/) const {
64 virtual const UnicodeString
*snext(UErrorCode
& status
);
65 virtual void reset(UErrorCode
& status
);
66 static inline UClassID
getStaticClassID() {
67 return (UClassID
)&fgClassID
;
69 virtual UClassID
getDynamicClassID() const {
70 return getStaticClassID();
73 static const char fgClassID
;
76 StringEnumeration
*tzenum
;
79 const char TestZIDEnumeration::fgClassID
= 0;
81 TestZIDEnumeration::TestZIDEnumeration(UBool all
)
83 UErrorCode status
= U_ZERO_ERROR
;
85 tzenum
= TimeZone::createEnumeration();
86 len
= tzenum
->count(status
);
89 len
= (int32_t)sizeof(TESTZIDS
)/sizeof(TESTZIDS
[0]);
93 TestZIDEnumeration::~TestZIDEnumeration() {
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
++], "");
111 TestZIDEnumeration::reset(UErrorCode
& status
) {
112 if (tzenum
!= NULL
) {
113 tzenum
->reset(status
);
120 void TimeZoneRuleTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/ )
123 logln("TestSuite TestTimeZoneRule");
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
);
142 CASE(16, TestVTimeZoneWrapper
);
144 default: name
= ""; break;
149 * Compare SimpleTimeZone with equivalent RBTZ
152 TimeZoneRuleTest::TestSimpleRuleBasedTimeZone(void) {
153 UErrorCode status
= U_ZERO_ERROR
;
154 SimpleTimeZone
stz(-1*HOUR
, "TestSTZ",
155 UCAL_SEPTEMBER
, -30, -UCAL_SATURDAY
, 1*HOUR
, SimpleTimeZone::WALL_TIME
,
156 UCAL_FEBRUARY
, 2, UCAL_SUNDAY
, 1*HOUR
, SimpleTimeZone::WALL_TIME
,
158 if (U_FAILURE(status
)) {
159 errln("FAIL: Couldn't create SimpleTimezone.");
163 AnnualTimeZoneRule
*atzr
;
164 int32_t STARTYEAR
= 2000;
166 InitialTimeZoneRule
*ir
= new InitialTimeZoneRule(
167 "RBTZ_Initial", // Initial time Name
168 -1*HOUR
, // Raw offset
169 1*HOUR
); // DST saving amount
172 RuleBasedTimeZone
*rbtz1
= new RuleBasedTimeZone("RBTZ1", ir
->clone());
173 dtr
= new DateTimeRule(UCAL_SEPTEMBER
, 30, UCAL_SATURDAY
, FALSE
,
174 1*HOUR
, DateTimeRule::WALL_TIME
); // SUN<=30 in September, at 1AM wall time
175 atzr
= new AnnualTimeZoneRule("RBTZ_DST1",
176 -1*HOUR
/*rawOffset*/, 1*HOUR
/*dstSavings*/, dtr
,
177 STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
178 rbtz1
->addTransitionRule(atzr
, status
);
179 if (U_FAILURE(status
)) {
180 errln("FAIL: couldn't add AnnualTimeZoneRule 1-1.");
182 dtr
= new DateTimeRule(UCAL_FEBRUARY
, 2, UCAL_SUNDAY
,
183 1*HOUR
, DateTimeRule::WALL_TIME
); // 2nd Sunday in February, at 1AM wall time
184 atzr
= new AnnualTimeZoneRule("RBTZ_STD1",
185 -1*HOUR
/*rawOffset*/, 0 /*dstSavings*/, dtr
,
186 STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
187 rbtz1
->addTransitionRule(atzr
, status
);
188 if (U_FAILURE(status
)) {
189 errln("FAIL: couldn't add AnnualTimeZoneRule 1-2.");
191 rbtz1
->complete(status
);
192 if (U_FAILURE(status
)) {
193 errln("FAIL: couldn't complete RBTZ 1.");
196 // Equivalent, but different date rule type
197 RuleBasedTimeZone
*rbtz2
= new RuleBasedTimeZone("RBTZ2", ir
->clone());
198 dtr
= new DateTimeRule(UCAL_SEPTEMBER
, -1, UCAL_SATURDAY
,
199 1*HOUR
, DateTimeRule::WALL_TIME
); // Last Sunday in September at 1AM wall time
200 atzr
= new AnnualTimeZoneRule("RBTZ_DST2", -1*HOUR
, 1*HOUR
, dtr
, STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
201 rbtz2
->addTransitionRule(atzr
, status
);
202 if (U_FAILURE(status
)) {
203 errln("FAIL: couldn't add AnnualTimeZoneRule 2-1.");
205 dtr
= new DateTimeRule(UCAL_FEBRUARY
, 8, UCAL_SUNDAY
, true,
206 1*HOUR
, DateTimeRule::WALL_TIME
); // SUN>=8 in February, at 1AM wall time
207 atzr
= new AnnualTimeZoneRule("RBTZ_STD2", -1*HOUR
, 0, dtr
, STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
208 rbtz2
->addTransitionRule(atzr
, status
);
209 if (U_FAILURE(status
)) {
210 errln("FAIL: couldn't add AnnualTimeZoneRule 2-2.");
212 rbtz2
->complete(status
);
213 if (U_FAILURE(status
)) {
214 errln("FAIL: couldn't complete RBTZ 2");
217 // Equivalent, but different time rule type
218 RuleBasedTimeZone
*rbtz3
= new RuleBasedTimeZone("RBTZ3", ir
->clone());
219 dtr
= new DateTimeRule(UCAL_SEPTEMBER
, 30, UCAL_SATURDAY
, false,
220 2*HOUR
, DateTimeRule::UTC_TIME
);
221 atzr
= new AnnualTimeZoneRule("RBTZ_DST3", -1*HOUR
, 1*HOUR
, dtr
, STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
222 rbtz3
->addTransitionRule(atzr
, status
);
223 if (U_FAILURE(status
)) {
224 errln("FAIL: couldn't add AnnualTimeZoneRule 3-1.");
226 dtr
= new DateTimeRule(UCAL_FEBRUARY
, 2, UCAL_SUNDAY
,
227 0*HOUR
, DateTimeRule::STANDARD_TIME
);
228 atzr
= new AnnualTimeZoneRule("RBTZ_STD3", -1*HOUR
, 0, dtr
, STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
229 rbtz3
->addTransitionRule(atzr
, status
);
230 if (U_FAILURE(status
)) {
231 errln("FAIL: couldn't add AnnualTimeZoneRule 3-2.");
233 rbtz3
->complete(status
);
234 if (U_FAILURE(status
)) {
235 errln("FAIL: couldn't complete RBTZ 3");
238 // Check equivalency for 10 years
239 UDate start
= getUTCMillis(STARTYEAR
, UCAL_JANUARY
, 1);
240 UDate until
= getUTCMillis(STARTYEAR
+ 10, UCAL_JANUARY
, 1);
242 if (!(stz
.hasEquivalentTransitions(*rbtz1
, start
, until
, TRUE
, status
))) {
243 errln("FAIL: rbtz1 must be equivalent to the SimpleTimeZone in the time range.");
245 if (U_FAILURE(status
)) {
246 errln("FAIL: error returned from hasEquivalentTransitions");
248 if (!(stz
.hasEquivalentTransitions(*rbtz2
, start
, until
, TRUE
, status
))) {
249 errln("FAIL: rbtz2 must be equivalent to the SimpleTimeZone in the time range.");
251 if (U_FAILURE(status
)) {
252 errln("FAIL: error returned from hasEquivalentTransitions");
254 if (!(stz
.hasEquivalentTransitions(*rbtz3
, start
, until
, TRUE
, status
))) {
255 errln("FAIL: rbtz3 must be equivalent to the SimpleTimeZone in the time range.");
257 if (U_FAILURE(status
)) {
258 errln("FAIL: error returned from hasEquivalentTransitions");
262 if (rbtz1
->hasSameRules(*rbtz2
)) {
263 errln("FAIL: rbtz1 and rbtz2 have different rules, but returned true.");
265 if (rbtz1
->hasSameRules(*rbtz3
)) {
266 errln("FAIL: rbtz1 and rbtz3 have different rules, but returned true.");
268 RuleBasedTimeZone
*rbtz1c
= (RuleBasedTimeZone
*)rbtz1
->clone();
269 if (!rbtz1
->hasSameRules(*rbtz1c
)) {
270 errln("FAIL: Cloned RuleBasedTimeZone must have the same rules with the original.");
274 int32_t era
, year
, month
, dayOfMonth
, dayOfWeek
, millisInDay
;
276 int32_t offset
, dstSavings
;
279 GregorianCalendar
*cal
= new GregorianCalendar(status
);
280 if (U_FAILURE(status
)) {
281 dataerrln("FAIL: Could not create a Gregorian calendar instance.: %s", u_errorName(status
));
288 cal
->setTimeZone(*rbtz1
);
292 cal
->set(UCAL_ERA
, GregorianCalendar::BC
);
293 cal
->set(1000, UCAL_JANUARY
, 1);
295 era
= cal
->get(UCAL_ERA
, status
);
296 year
= cal
->get(UCAL_YEAR
, status
);
297 month
= cal
->get(UCAL_MONTH
, status
);
298 dayOfMonth
= cal
->get(UCAL_DAY_OF_MONTH
, status
);
299 dayOfWeek
= cal
->get(UCAL_DAY_OF_WEEK
, status
);
300 millisInDay
= cal
->get(UCAL_MILLISECONDS_IN_DAY
, status
);
301 time
= cal
->getTime(status
);
302 if (U_FAILURE(status
)) {
303 errln("FAIL: Could not get calendar field values.");
305 offset
= rbtz1
->getOffset(era
, year
, month
, dayOfMonth
, dayOfWeek
, millisInDay
, status
);
306 if (U_FAILURE(status
)) {
307 errln("FAIL: getOffset(7 args) failed.");
310 errln(UnicodeString("FAIL: Invalid time zone offset: ") + offset
+ " /expected: 0");
312 dst
= rbtz1
->inDaylightTime(time
, status
);
313 if (U_FAILURE(status
)) {
314 errln("FAIL: inDaylightTime failed.");
317 errln("FAIL: Invalid daylight saving time");
319 rbtz1
->getOffset(time
, TRUE
, offset
, dstSavings
, status
);
320 if (U_FAILURE(status
)) {
321 errln("FAIL: getOffset(5 args) failed.");
323 if (offset
!= -3600000) {
324 errln(UnicodeString("FAIL: Invalid time zone raw offset: ") + offset
+ " /expected: -3600000");
326 if (dstSavings
!= 3600000) {
327 errln(UnicodeString("FAIL: Invalid DST amount: ") + dstSavings
+ " /expected: 3600000");
331 cal
->set(UCAL_ERA
, GregorianCalendar::AD
);
332 cal
->set(2000, UCAL_JULY
, 1);
334 era
= cal
->get(UCAL_ERA
, status
);
335 year
= cal
->get(UCAL_YEAR
, status
);
336 month
= cal
->get(UCAL_MONTH
, status
);
337 dayOfMonth
= cal
->get(UCAL_DAY_OF_MONTH
, status
);
338 dayOfWeek
= cal
->get(UCAL_DAY_OF_WEEK
, status
);
339 millisInDay
= cal
->get(UCAL_MILLISECONDS_IN_DAY
, status
);
340 time
= cal
->getTime(status
);
341 if (U_FAILURE(status
)) {
342 errln("FAIL: Could not get calendar field values.");
344 offset
= rbtz1
->getOffset(era
, year
, month
, dayOfMonth
, dayOfWeek
, millisInDay
, status
);
345 if (U_FAILURE(status
)) {
346 errln("FAIL: getOffset(7 args) failed.");
348 if (offset
!= -3600000) {
349 errln((UnicodeString
)"FAIL: Invalid time zone offset: " + offset
+ " /expected: -3600000");
351 dst
= rbtz1
->inDaylightTime(time
, status
);
352 if (U_FAILURE(status
)) {
353 errln("FAIL: inDaylightTime failed.");
356 errln("FAIL: Invalid daylight saving time");
358 rbtz1
->getOffset(time
, TRUE
, offset
, dstSavings
, status
);
359 if (U_FAILURE(status
)) {
360 errln("FAIL: getOffset(5 args) failed.");
362 if (offset
!= -3600000) {
363 errln((UnicodeString
)"FAIL: Invalid time zone raw offset: " + offset
+ " /expected: -3600000");
365 if (dstSavings
!= 0) {
366 errln((UnicodeString
)"FAIL: Invalid DST amount: " + dstSavings
+ " /expected: 0");
370 offset
= rbtz1
->getRawOffset();
371 if (offset
!= -1*HOUR
) {
372 errln((UnicodeString
)"FAIL: Invalid time zone raw offset returned by getRawOffset: "
373 + offset
+ " /expected: -3600000");
377 RuleBasedTimeZone
rbtz0("RBTZ1", ir
->clone());
378 if (rbtz0
== *rbtz1
|| !(rbtz0
!= *rbtz1
)) {
379 errln("FAIL: RuleBasedTimeZone rbtz0 is not equal to rbtz1, but got wrong result");
382 if (rbtz0
!= *rbtz1
|| !(rbtz0
== *rbtz1
)) {
383 errln("FAIL: RuleBasedTimeZone rbtz0 is equal to rbtz1, but got wrong result");
387 const int32_t RAW
= -10*HOUR
;
388 rbtz0
.setRawOffset(RAW
);
389 if (rbtz0
.getRawOffset() != RAW
) {
390 logln("setRawOffset is implemented in RuleBasedTimeZone");
394 if (!rbtz1
->useDaylightTime()) {
395 errln("FAIL: useDaylightTime returned FALSE");
398 // Try to add 3rd final rule
399 dtr
= new DateTimeRule(UCAL_OCTOBER
, 15, 1*HOUR
, DateTimeRule::WALL_TIME
);
400 atzr
= new AnnualTimeZoneRule("3RD_ATZ", -1*HOUR
, 2*HOUR
, dtr
, STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
401 rbtz1
->addTransitionRule(atzr
, status
);
402 if (U_SUCCESS(status
)) {
403 errln("FAIL: 3rd final rule must be rejected");
408 // Try to add an initial rule
409 InitialTimeZoneRule
*ir1
= new InitialTimeZoneRule("Test Initial", 2*HOUR
, 0);
410 rbtz1
->addTransitionRule(ir1
, status
);
411 if (U_SUCCESS(status
)) {
412 errln("FAIL: InitialTimeZoneRule must be rejected");
426 * Test equivalency between OlsonTimeZone and custom RBTZ representing the
427 * equivalent rules in a certain time range
430 TimeZoneRuleTest::TestHistoricalRuleBasedTimeZone(void) {
431 UErrorCode status
= U_ZERO_ERROR
;
433 // Compare to America/New_York with equivalent RBTZ
434 BasicTimeZone
*ny
= (BasicTimeZone
*)TimeZone::createTimeZone("America/New_York");
437 InitialTimeZoneRule
*ir
= new InitialTimeZoneRule("EST", -5*HOUR
, 0);
438 RuleBasedTimeZone
*rbtz
= new RuleBasedTimeZone("EST5EDT", ir
);
441 AnnualTimeZoneRule
*tzr
;
444 dtr
= new DateTimeRule(UCAL_OCTOBER
, -1, UCAL_SUNDAY
,
445 2*HOUR
, DateTimeRule::WALL_TIME
); // Last Sunday in October, at 2AM wall time
446 tzr
= new AnnualTimeZoneRule("EST", -5*HOUR
/*rawOffset*/, 0 /*dstSavings*/, dtr
, 1967, 2006);
447 rbtz
->addTransitionRule(tzr
, status
);
448 if (U_FAILURE(status
)) {
449 errln("FAIL: couldn't add AnnualTimeZoneRule 1.");
452 dtr
= new DateTimeRule(UCAL_NOVEMBER
, 1, UCAL_SUNDAY
,
453 true, 2*HOUR
, DateTimeRule::WALL_TIME
); // SUN>=1 in November, at 2AM wall time
454 tzr
= new AnnualTimeZoneRule("EST", -5*HOUR
, 0, dtr
, 2007, AnnualTimeZoneRule::MAX_YEAR
);
455 rbtz
->addTransitionRule(tzr
, status
);
456 if (U_FAILURE(status
)) {
457 errln("FAIL: couldn't add AnnualTimeZoneRule 2.");
460 // Daylight saving time
461 dtr
= new DateTimeRule(UCAL_APRIL
, -1, UCAL_SUNDAY
,
462 2*HOUR
, DateTimeRule::WALL_TIME
); // Last Sunday in April, at 2AM wall time
463 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 1967, 1973);
464 rbtz
->addTransitionRule(tzr
, status
);
465 if (U_FAILURE(status
)) {
466 errln("FAIL: couldn't add AnnualTimeZoneRule 3.");
469 dtr
= new DateTimeRule(UCAL_JANUARY
, 6,
470 2*HOUR
, DateTimeRule::WALL_TIME
); // January 6, at 2AM wall time
471 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 1974, 1974);
472 rbtz
->addTransitionRule(tzr
, status
);
473 if (U_FAILURE(status
)) {
474 errln("FAIL: couldn't add AnnualTimeZoneRule 4.");
477 dtr
= new DateTimeRule(UCAL_FEBRUARY
, 23,
478 2*HOUR
, DateTimeRule::WALL_TIME
); // February 23, at 2AM wall time
479 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 1975, 1975);
480 rbtz
->addTransitionRule(tzr
, status
);
481 if (U_FAILURE(status
)) {
482 errln("FAIL: couldn't add AnnualTimeZoneRule 5.");
485 dtr
= new DateTimeRule(UCAL_APRIL
, -1, UCAL_SUNDAY
,
486 2*HOUR
, DateTimeRule::WALL_TIME
); // Last Sunday in April, at 2AM wall time
487 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 1976, 1986);
488 rbtz
->addTransitionRule(tzr
, status
);
489 if (U_FAILURE(status
)) {
490 errln("FAIL: couldn't add AnnualTimeZoneRule 6.");
493 dtr
= new DateTimeRule(UCAL_APRIL
, 1, UCAL_SUNDAY
,
494 true, 2*HOUR
, DateTimeRule::WALL_TIME
); // SUN>=1 in April, at 2AM wall time
495 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 1987, 2006);
496 rbtz
->addTransitionRule(tzr
, status
);
497 if (U_FAILURE(status
)) {
498 errln("FAIL: couldn't add AnnualTimeZoneRule 7.");
501 dtr
= new DateTimeRule(UCAL_MARCH
, 8, UCAL_SUNDAY
,
502 true, 2*HOUR
, DateTimeRule::WALL_TIME
); // SUN>=8 in March, at 2AM wall time
503 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 2007, AnnualTimeZoneRule::MAX_YEAR
);
504 rbtz
->addTransitionRule(tzr
, status
);
505 if (U_FAILURE(status
)) {
506 errln("FAIL: couldn't add AnnualTimeZoneRule 7.");
509 rbtz
->complete(status
);
510 if (U_FAILURE(status
)) {
511 errln("FAIL: couldn't complete RBTZ.");
514 // hasEquivalentTransitions
515 UDate jan1_1950
= getUTCMillis(1950, UCAL_JANUARY
, 1);
516 UDate jan1_1967
= getUTCMillis(1971, UCAL_JANUARY
, 1);
517 UDate jan1_2010
= getUTCMillis(2010, UCAL_JANUARY
, 1);
519 if (!ny
->hasEquivalentTransitions(*rbtz
, jan1_1967
, jan1_2010
, TRUE
, status
)) {
520 dataerrln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010");
522 if (U_FAILURE(status
)) {
523 errln("FAIL: error returned from hasEquivalentTransitions for ny/rbtz 1967-2010");
525 if (ny
->hasEquivalentTransitions(*rbtz
, jan1_1950
, jan1_2010
, TRUE
, status
)) {
526 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010");
528 if (U_FAILURE(status
)) {
529 errln("FAIL: error returned from hasEquivalentTransitions for ny/rbtz 1950-2010");
532 // Same with above, but calling RBTZ#hasEquivalentTransitions against OlsonTimeZone
533 if (!rbtz
->hasEquivalentTransitions(*ny
, jan1_1967
, jan1_2010
, TRUE
, status
)) {
534 dataerrln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010 ");
536 if (U_FAILURE(status
)) {
537 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/ny 1967-2010");
539 if (rbtz
->hasEquivalentTransitions(*ny
, jan1_1950
, jan1_2010
, TRUE
, status
)) {
540 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010");
542 if (U_FAILURE(status
)) {
543 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/ny 1950-2010");
547 if (ny
->hasSameRules(*rbtz
) || rbtz
->hasSameRules(*ny
)) {
548 errln("FAIL: hasSameRules must return false");
550 RuleBasedTimeZone
*rbtzc
= (RuleBasedTimeZone
*)rbtz
->clone();
551 if (!rbtz
->hasSameRules(*rbtzc
) || !rbtz
->hasEquivalentTransitions(*rbtzc
, jan1_1950
, jan1_2010
, TRUE
, status
)) {
552 errln("FAIL: hasSameRules/hasEquivalentTransitions must return true for cloned RBTZs");
554 if (U_FAILURE(status
)) {
555 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/rbtzc 1950-2010");
559 getUTCMillis(2006, UCAL_MARCH
, 15),
560 getUTCMillis(2006, UCAL_NOVEMBER
, 1),
561 getUTCMillis(2007, UCAL_MARCH
, 15),
562 getUTCMillis(2007, UCAL_NOVEMBER
, 1),
563 getUTCMillis(2008, UCAL_MARCH
, 15),
564 getUTCMillis(2008, UCAL_NOVEMBER
, 1),
567 int32_t offset1
, dst1
;
568 int32_t offset2
, dst2
;
570 for (int i
= 0; times
[i
] != 0; i
++) {
571 // Check getOffset - must return the same results for these time data
572 rbtz
->getOffset(times
[i
], FALSE
, offset1
, dst1
, status
);
573 if (U_FAILURE(status
)) {
574 errln("FAIL: rbtz->getOffset failed");
576 ny
->getOffset(times
[i
], FALSE
, offset2
, dst2
, status
);
577 if (U_FAILURE(status
)) {
578 errln("FAIL: ny->getOffset failed");
580 if (offset1
!= offset2
|| dst1
!= dst2
) {
581 dataerrln("FAIL: Incompatible time zone offset/dstSavings for ny and rbtz");
584 // Check inDaylightTime
585 if (rbtz
->inDaylightTime(times
[i
], status
) != ny
->inDaylightTime(times
[i
], status
)) {
586 dataerrln("FAIL: Incompatible daylight saving time for ny and rbtz");
588 if (U_FAILURE(status
)) {
589 errln("FAIL: inDaylightTime failed");
599 * Check if transitions returned by getNextTransition/getPreviousTransition
600 * are actual time transitions.
603 TimeZoneRuleTest::TestOlsonTransition(void) {
605 const int32_t TESTYEARS
[][2] = {
606 {1895, 1905}, // including int32 minimum second
607 {1965, 1975}, // including the epoch
608 {1995, 2015}, // practical year range
612 UErrorCode status
= U_ZERO_ERROR
;
613 TestZIDEnumeration
tzenum(!quick
);
615 const UnicodeString
*tzid
= tzenum
.snext(status
);
619 if (U_FAILURE(status
)) {
620 errln("FAIL: error returned while enumerating timezone IDs.");
623 BasicTimeZone
*tz
= (BasicTimeZone
*)TimeZone::createTimeZone(*tzid
);
624 for (int32_t i
= 0; TESTYEARS
[i
][0] != 0 || TESTYEARS
[i
][1] != 0; i
++) {
625 UDate lo
= getUTCMillis(TESTYEARS
[i
][0], UCAL_JANUARY
, 1);
626 UDate hi
= getUTCMillis(TESTYEARS
[i
][1], UCAL_JANUARY
, 1);
627 verifyTransitions(*tz
, lo
, hi
);
634 * Check if an OlsonTimeZone and its equivalent RBTZ have the exact same
638 TimeZoneRuleTest::TestRBTZTransition(void) {
639 const int32_t STARTYEARS
[] = {
647 UErrorCode status
= U_ZERO_ERROR
;
648 TestZIDEnumeration
tzenum(!quick
);
650 const UnicodeString
*tzid
= tzenum
.snext(status
);
654 if (U_FAILURE(status
)) {
655 errln("FAIL: error returned while enumerating timezone IDs.");
658 BasicTimeZone
*tz
= (BasicTimeZone
*)TimeZone::createTimeZone(*tzid
);
659 int32_t ruleCount
= tz
->countTransitionRules(status
);
661 const InitialTimeZoneRule
*initial
;
662 const TimeZoneRule
**trsrules
= new const TimeZoneRule
*[ruleCount
];
663 tz
->getTimeZoneRules(initial
, trsrules
, ruleCount
, status
);
664 if (U_FAILURE(status
)) {
665 errln((UnicodeString
)"FAIL: failed to get the TimeZoneRules from time zone " + *tzid
);
667 RuleBasedTimeZone
*rbtz
= new RuleBasedTimeZone(*tzid
, initial
->clone());
668 if (U_FAILURE(status
)) {
669 errln((UnicodeString
)"FAIL: failed to get the transition rule count from time zone " + *tzid
);
671 for (int32_t i
= 0; i
< ruleCount
; i
++) {
672 rbtz
->addTransitionRule(trsrules
[i
]->clone(), status
);
673 if (U_FAILURE(status
)) {
674 errln((UnicodeString
)"FAIL: failed to add a transition rule at index " + i
+ " to the RBTZ for " + *tzid
);
677 rbtz
->complete(status
);
678 if (U_FAILURE(status
)) {
679 errln((UnicodeString
)"FAIL: complete() failed for the RBTZ for " + *tzid
);
682 for (int32_t idx
= 0; STARTYEARS
[idx
] != 0; idx
++) {
683 UDate start
= getUTCMillis(STARTYEARS
[idx
], UCAL_JANUARY
, 1);
684 UDate until
= getUTCMillis(STARTYEARS
[idx
] + 20, UCAL_JANUARY
, 1);
685 // Compare the original OlsonTimeZone with the RBTZ starting the startTime for 20 years
688 compareTransitionsAscending(*tz
, *rbtz
, start
, until
, FALSE
);
689 // Ascending/inclusive
690 compareTransitionsAscending(*tz
, *rbtz
, start
+ 1, until
, TRUE
);
692 compareTransitionsDescending(*tz
, *rbtz
, start
, until
, FALSE
);
693 // Descending/inclusive
694 compareTransitionsDescending(*tz
, *rbtz
, start
+ 1, until
, TRUE
);
703 TimeZoneRuleTest::TestHasEquivalentTransitions(void) {
704 // America/New_York and America/Indiana/Indianapolis are equivalent
706 UErrorCode status
= U_ZERO_ERROR
;
707 BasicTimeZone
*newyork
= (BasicTimeZone
*)TimeZone::createTimeZone("America/New_York");
708 BasicTimeZone
*indianapolis
= (BasicTimeZone
*)TimeZone::createTimeZone("America/Indiana/Indianapolis");
709 BasicTimeZone
*gmt_5
= (BasicTimeZone
*)TimeZone::createTimeZone("Etc/GMT+5");
711 UDate jan1_1971
= getUTCMillis(1971, UCAL_JANUARY
, 1);
712 UDate jan1_2005
= getUTCMillis(2005, UCAL_JANUARY
, 1);
713 UDate jan1_2006
= getUTCMillis(2006, UCAL_JANUARY
, 1);
714 UDate jan1_2007
= getUTCMillis(2007, UCAL_JANUARY
, 1);
715 UDate jan1_2011
= getUTCMillis(2010, UCAL_JANUARY
, 1);
717 if (newyork
->hasEquivalentTransitions(*indianapolis
, jan1_2005
, jan1_2011
, TRUE
, status
)) {
718 dataerrln("FAIL: New_York is not equivalent to Indianapolis between 2005 and 2010");
720 if (U_FAILURE(status
)) {
721 errln("FAIL: error status is returned from hasEquivalentTransition");
723 if (!newyork
->hasEquivalentTransitions(*indianapolis
, jan1_2006
, jan1_2011
, TRUE
, status
)) {
724 errln("FAIL: New_York is equivalent to Indianapolis between 2006 and 2010");
726 if (U_FAILURE(status
)) {
727 errln("FAIL: error status is returned from hasEquivalentTransition");
730 if (!indianapolis
->hasEquivalentTransitions(*gmt_5
, jan1_1971
, jan1_2006
, TRUE
, status
)) {
731 errln("FAIL: Indianapolis is equivalent to GMT+5 between 1971 and 2005");
733 if (U_FAILURE(status
)) {
734 errln("FAIL: error status is returned from hasEquivalentTransition");
736 if (indianapolis
->hasEquivalentTransitions(*gmt_5
, jan1_1971
, jan1_2007
, TRUE
, status
)) {
737 dataerrln("FAIL: Indianapolis is not equivalent to GMT+5 between 1971 and 2006");
739 if (U_FAILURE(status
)) {
740 errln("FAIL: error status is returned from hasEquivalentTransition");
744 BasicTimeZone
*newyork2
= (BasicTimeZone
*)newyork
->clone();
745 if (!newyork
->hasEquivalentTransitions(*newyork2
, jan1_1971
, jan1_2011
, FALSE
, status
)) {
746 errln("FAIL: Cloned TimeZone must have the same transitions");
748 if (U_FAILURE(status
)) {
749 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/newyork2");
751 if (!newyork
->hasEquivalentTransitions(*newyork2
, jan1_1971
, jan1_2011
, TRUE
, status
)) {
752 errln("FAIL: Cloned TimeZone must have the same transitions");
754 if (U_FAILURE(status
)) {
755 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/newyork2");
758 // America/New_York and America/Los_Angeles has same DST start rules, but
759 // raw offsets are different
760 BasicTimeZone
*losangeles
= (BasicTimeZone
*)TimeZone::createTimeZone("America/Los_Angeles");
761 if (newyork
->hasEquivalentTransitions(*losangeles
, jan1_2006
, jan1_2011
, TRUE
, status
)) {
762 dataerrln("FAIL: New_York is not equivalent to Los Angeles, but returned true");
764 if (U_FAILURE(status
)) {
765 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/losangeles");
776 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format, create a new
777 * VTimeZone from the VTIMEZONE data, then compare transitions
780 TimeZoneRuleTest::TestVTimeZoneRoundTrip(void) {
781 UDate startTime
= getUTCMillis(1850, UCAL_JANUARY
, 1);
782 UDate endTime
= getUTCMillis(2050, UCAL_JANUARY
, 1);
784 UErrorCode status
= U_ZERO_ERROR
;
785 TestZIDEnumeration
tzenum(!quick
);
787 const UnicodeString
*tzid
= tzenum
.snext(status
);
791 if (U_FAILURE(status
)) {
792 errln("FAIL: error returned while enumerating timezone IDs.");
795 BasicTimeZone
*tz
= (BasicTimeZone
*)TimeZone::createTimeZone(*tzid
);
796 VTimeZone
*vtz_org
= VTimeZone::createVTimeZoneByID(*tzid
);
797 vtz_org
->setTZURL("http://source.icu-project.org/timezone");
798 vtz_org
->setLastModified(Calendar::getNow());
799 VTimeZone
*vtz_new
= NULL
;
800 UnicodeString vtzdata
;
801 // Write out VTIMEZONE data
802 vtz_org
->write(vtzdata
, status
);
803 if (U_FAILURE(status
)) {
804 errln((UnicodeString
)"FAIL: error returned while writing time zone rules for " +
805 *tzid
+ " into VTIMEZONE format.");
807 // Read VTIMEZONE data
808 vtz_new
= VTimeZone::createVTimeZone(vtzdata
, status
);
809 if (U_FAILURE(status
)) {
810 errln((UnicodeString
)"FAIL: error returned while reading VTIMEZONE data for " + *tzid
);
812 // Write out VTIMEZONE one more time
813 UnicodeString vtzdata1
;
814 vtz_new
->write(vtzdata1
, status
);
815 if (U_FAILURE(status
)) {
816 errln((UnicodeString
)"FAIL: error returned while writing time zone rules for " +
817 *tzid
+ "(vtz_new) into VTIMEZONE format.");
819 // Make sure VTIMEZONE data is exactly same with the first one
820 if (vtzdata
!= vtzdata1
) {
821 errln((UnicodeString
)"FAIL: different VTIMEZONE data after round trip for " + *tzid
);
824 // Check equivalency after the first transition.
825 // The DST information before the first transition might be lost
826 // because there is no good way to represent the initial time with
828 int32_t raw1
, raw2
, dst1
, dst2
;
829 tz
->getOffset(startTime
, FALSE
, raw1
, dst1
, status
);
830 vtz_new
->getOffset(startTime
, FALSE
, raw2
, dst2
, status
);
831 if (U_FAILURE(status
)) {
832 errln("FAIL: error status is returned from getOffset");
834 if (raw1
+ dst1
!= raw2
+ dst2
) {
835 errln("FAIL: VTimeZone for " + *tzid
+
836 " is not equivalent to its OlsonTimeZone corresponding at "
837 + dateToString(startTime
));
839 TimeZoneTransition trans
;
840 UBool avail
= tz
->getNextTransition(startTime
, FALSE
, trans
);
842 if (!vtz_new
->hasEquivalentTransitions(*tz
, trans
.getTime(),
843 endTime
, TRUE
, status
)) {
844 int32_t maxDelta
= 1000;
845 if (!hasEquivalentTransitions(*vtz_new
, *tz
, trans
.getTime() + maxDelta
,
846 endTime
, TRUE
, maxDelta
, status
)) {
847 errln("FAIL: VTimeZone for " + *tzid
+
848 " is not equivalent to its OlsonTimeZone corresponding.");
850 logln("VTimeZone for " + *tzid
+
851 " differs from its OlsonTimeZone corresponding with maximum transition time delta - " + maxDelta
);
854 if (U_FAILURE(status
)) {
855 errln("FAIL: error status is returned from hasEquivalentTransition");
860 if (vtz_new
!= NULL
) {
871 * Write out time zone rules of OlsonTimeZone after a cutover date into VTIMEZONE format,
872 * create a new VTimeZone from the VTIMEZONE data, then compare transitions
875 TimeZoneRuleTest::TestVTimeZoneRoundTripPartial(void) {
876 const int32_t STARTYEARS
[] = {
882 UDate endTime
= getUTCMillis(2050, UCAL_JANUARY
, 1);
884 UErrorCode status
= U_ZERO_ERROR
;
885 TestZIDEnumeration
tzenum(!quick
);
887 const UnicodeString
*tzid
= tzenum
.snext(status
);
891 if (U_FAILURE(status
)) {
892 errln("FAIL: error returned while enumerating timezone IDs.");
895 BasicTimeZone
*tz
= (BasicTimeZone
*)TimeZone::createTimeZone(*tzid
);
896 VTimeZone
*vtz_org
= VTimeZone::createVTimeZoneByID(*tzid
);
897 VTimeZone
*vtz_new
= NULL
;
898 UnicodeString vtzdata
;
900 for (int32_t i
= 0; STARTYEARS
[i
] != 0; i
++) {
901 // Write out VTIMEZONE
902 UDate startTime
= getUTCMillis(STARTYEARS
[i
], UCAL_JANUARY
, 1);
903 vtz_org
->write(startTime
, vtzdata
, status
);
904 if (U_FAILURE(status
)) {
905 errln((UnicodeString
)"FAIL: error returned while writing time zone rules for " +
906 *tzid
+ " into VTIMEZONE format since " + dateToString(startTime
));
908 // Read VTIMEZONE data
909 vtz_new
= VTimeZone::createVTimeZone(vtzdata
, status
);
910 if (U_FAILURE(status
)) {
911 errln((UnicodeString
)"FAIL: error returned while reading VTIMEZONE data for " + *tzid
912 + " since " + dateToString(startTime
));
914 // Check equivalency after the first transition.
915 // The DST information before the first transition might be lost
916 // because there is no good way to represent the initial time with
918 int32_t raw1
, raw2
, dst1
, dst2
;
919 tz
->getOffset(startTime
, FALSE
, raw1
, dst1
, status
);
920 vtz_new
->getOffset(startTime
, FALSE
, raw2
, dst2
, status
);
921 if (U_FAILURE(status
)) {
922 errln("FAIL: error status is returned from getOffset");
924 if (raw1
+ dst1
!= raw2
+ dst2
) {
925 errln("FAIL: VTimeZone for " + *tzid
+
926 " is not equivalent to its OlsonTimeZone corresponding at "
927 + dateToString(startTime
));
929 TimeZoneTransition trans
;
930 UBool avail
= tz
->getNextTransition(startTime
, FALSE
, trans
);
932 if (!vtz_new
->hasEquivalentTransitions(*tz
, trans
.getTime(),
933 endTime
, TRUE
, status
)) {
934 int32_t maxDelta
= 1000;
935 if (!hasEquivalentTransitions(*vtz_new
, *tz
, trans
.getTime() + maxDelta
,
936 endTime
, TRUE
, maxDelta
, status
)) {
937 errln("FAIL: VTimeZone for " + *tzid
+
938 " is not equivalent to its OlsonTimeZone corresponding.");
940 logln("VTimeZone for " + *tzid
+
941 " differs from its OlsonTimeZone corresponding with maximum transition time delta - " + maxDelta
);
945 if (U_FAILURE(status
)) {
946 errln("FAIL: error status is returned from hasEquivalentTransition");
952 if (vtz_new
!= NULL
) {
963 * Write out simple time zone rules from an OlsonTimeZone at various time into VTIMEZONE
964 * format and create a new VTimeZone from the VTIMEZONE data, then make sure the raw offset
965 * and DST savings are same in these two time zones.
968 TimeZoneRuleTest::TestVTimeZoneSimpleWrite(void) {
969 const int32_t TESTDATES
[][3] = {
970 {2006, UCAL_JANUARY
, 1},
971 {2006, UCAL_MARCH
, 15},
972 {2006, UCAL_MARCH
, 31},
973 {2006, UCAL_OCTOBER
, 25},
974 {2006, UCAL_NOVEMBER
, 1},
975 {2006, UCAL_NOVEMBER
, 5},
976 {2007, UCAL_JANUARY
, 1},
980 UErrorCode status
= U_ZERO_ERROR
;
981 TestZIDEnumeration
tzenum(!quick
);
983 const UnicodeString
*tzid
= tzenum
.snext(status
);
987 if (U_FAILURE(status
)) {
988 errln("FAIL: error returned while enumerating timezone IDs.");
991 VTimeZone
*vtz_org
= VTimeZone::createVTimeZoneByID(*tzid
);
992 VTimeZone
*vtz_new
= NULL
;
993 UnicodeString vtzdata
;
995 for (int32_t i
= 0; TESTDATES
[i
][0] != 0; i
++) {
996 // Write out VTIMEZONE
997 UDate time
= getUTCMillis(TESTDATES
[i
][0], TESTDATES
[i
][1], TESTDATES
[i
][2]);
998 vtz_org
->writeSimple(time
, vtzdata
, status
);
999 if (U_FAILURE(status
)) {
1000 errln((UnicodeString
)"FAIL: error returned while writing simple time zone rules for " +
1001 *tzid
+ " into VTIMEZONE format at " + dateToString(time
));
1003 // Read VTIMEZONE data
1004 vtz_new
= VTimeZone::createVTimeZone(vtzdata
, status
);
1005 if (U_FAILURE(status
)) {
1006 errln((UnicodeString
)"FAIL: error returned while reading simple VTIMEZONE data for " + *tzid
1007 + " at " + dateToString(time
));
1009 // Check equivalency
1012 vtz_org
->getOffset(time
, FALSE
, raw0
, dst0
, status
);
1013 vtz_new
->getOffset(time
, FALSE
, raw1
, dst1
, status
);
1014 if (U_SUCCESS(status
)) {
1015 if (raw0
!= raw1
|| dst0
!= dst1
) {
1016 errln("FAIL: VTimeZone writeSimple for " + *tzid
+ " at "
1017 + dateToString(time
) + " failed to the round trip.");
1020 errln("FAIL: getOffset returns error status");
1024 if (vtz_new
!= NULL
) {
1034 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format with RFC2445 header TZURL and
1035 * LAST-MODIFIED, create a new VTimeZone from the VTIMEZONE data to see if the headers are preserved.
1038 TimeZoneRuleTest::TestVTimeZoneHeaderProps(void) {
1039 const UnicodeString
TESTURL1("http://source.icu-project.org");
1040 const UnicodeString
TESTURL2("http://www.ibm.com");
1042 UErrorCode status
= U_ZERO_ERROR
;
1043 UnicodeString tzurl
;
1045 UDate lastmod
= getUTCMillis(2007, UCAL_JUNE
, 1);
1046 VTimeZone
*vtz
= VTimeZone::createVTimeZoneByID("America/Chicago");
1047 vtz
->setTZURL(TESTURL1
);
1048 vtz
->setLastModified(lastmod
);
1050 // Roundtrip conversion
1051 UnicodeString vtzdata
;
1052 vtz
->write(vtzdata
, status
);
1053 VTimeZone
*newvtz1
= NULL
;
1054 if (U_FAILURE(status
)) {
1055 errln("FAIL: error returned while writing VTIMEZONE data 1");
1059 newvtz1
= VTimeZone::createVTimeZone(vtzdata
, status
);
1060 if (U_FAILURE(status
)) {
1061 errln("FAIL: error returned while loading VTIMEZONE data 1");
1063 // Check if TZURL and LAST-MODIFIED properties are preserved
1064 newvtz1
->getTZURL(tzurl
);
1065 if (tzurl
!= TESTURL1
) {
1066 errln("FAIL: TZURL 1 was not preserved");
1068 vtz
->getLastModified(lmod
);
1069 if (lastmod
!= lmod
) {
1070 errln("FAIL: LAST-MODIFIED was not preserved");
1074 if (U_SUCCESS(status
)) {
1075 // Set different tzurl
1076 newvtz1
->setTZURL(TESTURL2
);
1078 // Second roundtrip, with a cutover
1079 newvtz1
->write(vtzdata
, status
);
1080 if (U_FAILURE(status
)) {
1081 errln("FAIL: error returned while writing VTIMEZONE data 2");
1083 VTimeZone
*newvtz2
= VTimeZone::createVTimeZone(vtzdata
, status
);
1084 if (U_FAILURE(status
)) {
1085 errln("FAIL: error returned while loading VTIMEZONE data 2");
1087 // Check if TZURL and LAST-MODIFIED properties are preserved
1088 newvtz2
->getTZURL(tzurl
);
1089 if (tzurl
!= TESTURL2
) {
1090 errln("FAIL: TZURL was not preserved in the second roundtrip");
1092 vtz
->getLastModified(lmod
);
1093 if (lastmod
!= lmod
) {
1094 errln("FAIL: LAST-MODIFIED was not preserved in the second roundtrip");
1105 * Extract simple rules from an OlsonTimeZone and make sure the rule format matches
1106 * the expected format.
1109 TimeZoneRuleTest::TestGetSimpleRules(void) {
1110 UDate testTimes
[] = {
1111 getUTCMillis(1970, UCAL_JANUARY
, 1),
1112 getUTCMillis(2000, UCAL_MARCH
, 31),
1113 getUTCMillis(2005, UCAL_JULY
, 1),
1114 getUTCMillis(2010, UCAL_NOVEMBER
, 1),
1116 int32_t numTimes
= sizeof(testTimes
)/sizeof(UDate
);
1117 UErrorCode status
= U_ZERO_ERROR
;
1118 TestZIDEnumeration
tzenum(!quick
);
1119 InitialTimeZoneRule
*initial
;
1120 AnnualTimeZoneRule
*std
, *dst
;
1121 for (int32_t i
= 0; i
< numTimes
; i
++) {
1123 const UnicodeString
*tzid
= tzenum
.snext(status
);
1127 if (U_FAILURE(status
)) {
1128 errln("FAIL: error returned while enumerating timezone IDs.");
1131 BasicTimeZone
*tz
= (BasicTimeZone
*)TimeZone::createTimeZone(*tzid
);
1134 tz
->getSimpleRulesNear(testTimes
[i
], initial
, std
, dst
, status
);
1135 if (U_FAILURE(status
)) {
1136 errln("FAIL: getSimpleRules failed.");
1139 if (initial
== NULL
) {
1140 errln("FAIL: initial rule must not be NULL");
1142 } else if (!((std
== NULL
&& dst
== NULL
) || (std
!= NULL
&& dst
!= NULL
))) {
1143 errln("FAIL: invalid std/dst pair.");
1147 const DateTimeRule
*dtr
= std
->getRule();
1148 if (dtr
->getDateRuleType() != DateTimeRule::DOW
) {
1149 errln("FAIL: simple std rull must use DateTimeRule::DOW as date rule.");
1152 if (dtr
->getTimeRuleType() != DateTimeRule::WALL_TIME
) {
1153 errln("FAIL: simple std rull must use DateTimeRule::WALL_TIME as time rule.");
1156 dtr
= dst
->getRule();
1157 if (dtr
->getDateRuleType() != DateTimeRule::DOW
) {
1158 errln("FAIL: simple dst rull must use DateTimeRule::DOW as date rule.");
1161 if (dtr
->getTimeRuleType() != DateTimeRule::WALL_TIME
) {
1162 errln("FAIL: simple dst rull must use DateTimeRule::WALL_TIME as time rule.");
1166 // Create an RBTZ from the rules and compare the offsets at the date
1167 RuleBasedTimeZone
*rbtz
= new RuleBasedTimeZone(*tzid
, initial
);
1169 rbtz
->addTransitionRule(std
, status
);
1170 if (U_FAILURE(status
)) {
1171 errln("FAIL: couldn't add std rule.");
1173 rbtz
->addTransitionRule(dst
, status
);
1174 if (U_FAILURE(status
)) {
1175 errln("FAIL: couldn't add dst rule.");
1178 rbtz
->complete(status
);
1179 if (U_FAILURE(status
)) {
1180 errln("FAIL: couldn't complete rbtz for " + *tzid
);
1183 int32_t raw0
, dst0
, raw1
, dst1
;
1184 tz
->getOffset(testTimes
[i
], FALSE
, raw0
, dst0
, status
);
1185 if (U_FAILURE(status
)) {
1186 errln("FAIL: couldn't get offsets from tz for " + *tzid
);
1188 rbtz
->getOffset(testTimes
[i
], FALSE
, raw1
, dst1
, status
);
1189 if (U_FAILURE(status
)) {
1190 errln("FAIL: couldn't get offsets from rbtz for " + *tzid
);
1192 if (raw0
!= raw1
|| dst0
!= dst1
) {
1193 errln("FAIL: rbtz created by simple rule does not match the original tz for tzid " + *tzid
);
1202 * API coverage tests for TimeZoneRule
1205 TimeZoneRuleTest::TestTimeZoneRuleCoverage(void) {
1206 UDate time1
= getUTCMillis(2005, UCAL_JULY
, 4);
1207 UDate time2
= getUTCMillis(2015, UCAL_JULY
, 4);
1208 UDate time3
= getUTCMillis(1950, UCAL_JULY
, 4);
1210 DateTimeRule
*dtr1
= new DateTimeRule(UCAL_FEBRUARY
, 29, UCAL_SUNDAY
, FALSE
,
1211 3*HOUR
, DateTimeRule::WALL_TIME
); // Last Sunday on or before Feb 29, at 3 AM, wall time
1212 DateTimeRule
*dtr2
= new DateTimeRule(UCAL_MARCH
, 11, 2*HOUR
,
1213 DateTimeRule::STANDARD_TIME
); // Mar 11, at 2 AM, standard time
1214 DateTimeRule
*dtr3
= new DateTimeRule(UCAL_OCTOBER
, -1, UCAL_SATURDAY
,
1215 6*HOUR
, DateTimeRule::UTC_TIME
); //Last Saturday in Oct, at 6 AM, UTC
1216 DateTimeRule
*dtr4
= new DateTimeRule(UCAL_MARCH
, 8, UCAL_SUNDAY
, TRUE
,
1217 2*HOUR
, DateTimeRule::WALL_TIME
); // First Sunday on or after Mar 8, at 2 AM, wall time
1219 AnnualTimeZoneRule
*a1
= new AnnualTimeZoneRule("a1", -3*HOUR
, 1*HOUR
, *dtr1
,
1220 2000, AnnualTimeZoneRule::MAX_YEAR
);
1221 AnnualTimeZoneRule
*a2
= new AnnualTimeZoneRule("a2", -3*HOUR
, 1*HOUR
, *dtr1
,
1222 2000, AnnualTimeZoneRule::MAX_YEAR
);
1223 AnnualTimeZoneRule
*a3
= new AnnualTimeZoneRule("a3", -3*HOUR
, 1*HOUR
, *dtr1
,
1226 InitialTimeZoneRule
*i1
= new InitialTimeZoneRule("i1", -3*HOUR
, 0);
1227 InitialTimeZoneRule
*i2
= new InitialTimeZoneRule("i2", -3*HOUR
, 0);
1228 InitialTimeZoneRule
*i3
= new InitialTimeZoneRule("i3", -3*HOUR
, 1*HOUR
);
1230 UDate trtimes1
[] = {0.0};
1231 UDate trtimes2
[] = {0.0, 10000000.0};
1233 TimeArrayTimeZoneRule
*t1
= new TimeArrayTimeZoneRule("t1", -3*HOUR
, 0, trtimes1
, 1, DateTimeRule::UTC_TIME
);
1234 TimeArrayTimeZoneRule
*t2
= new TimeArrayTimeZoneRule("t2", -3*HOUR
, 0, trtimes1
, 1, DateTimeRule::UTC_TIME
);
1235 TimeArrayTimeZoneRule
*t3
= new TimeArrayTimeZoneRule("t3", -3*HOUR
, 0, trtimes2
, 2, DateTimeRule::UTC_TIME
);
1236 TimeArrayTimeZoneRule
*t4
= new TimeArrayTimeZoneRule("t4", -3*HOUR
, 0, trtimes1
, 1, DateTimeRule::STANDARD_TIME
);
1237 TimeArrayTimeZoneRule
*t5
= new TimeArrayTimeZoneRule("t5", -4*HOUR
, 1*HOUR
, trtimes1
, 1, DateTimeRule::WALL_TIME
);
1239 // DateTimeRule::operator=/clone
1240 DateTimeRule
dtr0(UCAL_MAY
, 31, 2*HOUR
, DateTimeRule::WALL_TIME
);
1241 if (dtr0
== *dtr1
|| !(dtr0
!= *dtr1
)) {
1242 errln("FAIL: DateTimeRule dtr0 is not equal to dtr1, but got wrong result");
1245 if (dtr0
!= *dtr1
|| !(dtr0
== *dtr1
)) {
1246 errln("FAIL: DateTimeRule dtr0 is equal to dtr1, but got wrong result");
1248 DateTimeRule
*dtr0c
= dtr0
.clone();
1249 if (*dtr0c
!= *dtr1
|| !(*dtr0c
== *dtr1
)) {
1250 errln("FAIL: DateTimeRule dtr0c is equal to dtr1, but got wrong result");
1254 // AnnualTimeZonerule::operator=/clone
1255 AnnualTimeZoneRule
a0("a0", 5*HOUR
, 1*HOUR
, *dtr1
, 1990, AnnualTimeZoneRule::MAX_YEAR
);
1256 if (a0
== *a1
|| !(a0
!= *a1
)) {
1257 errln("FAIL: AnnualTimeZoneRule a0 is not equal to a1, but got wrong result");
1260 if (a0
!= *a1
|| !(a0
== *a1
)) {
1261 errln("FAIL: AnnualTimeZoneRule a0 is equal to a1, but got wrong result");
1263 AnnualTimeZoneRule
*a0c
= a0
.clone();
1264 if (*a0c
!= *a1
|| !(*a0c
== *a1
)) {
1265 errln("FAIL: AnnualTimeZoneRule a0c is equal to a1, but got wrong result");
1269 // AnnualTimeZoneRule::getRule
1270 if (*(a1
->getRule()) != *(a2
->getRule())) {
1271 errln("FAIL: The same DateTimeRule must be returned from AnnualTimeZoneRule a1 and a2");
1274 // AnnualTimeZoneRule::getStartYear
1275 int32_t startYear
= a1
->getStartYear();
1276 if (startYear
!= 2000) {
1277 errln((UnicodeString
)"FAIL: The start year of AnnualTimeZoneRule a1 must be 2000 - returned: " + startYear
);
1280 // AnnualTimeZoneRule::getEndYear
1281 int32_t endYear
= a1
->getEndYear();
1282 if (endYear
!= AnnualTimeZoneRule::MAX_YEAR
) {
1283 errln((UnicodeString
)"FAIL: The start year of AnnualTimeZoneRule a1 must be MAX_YEAR - returned: " + endYear
);
1285 endYear
= a3
->getEndYear();
1286 if (endYear
!= 2010) {
1287 errln((UnicodeString
)"FAIL: The start year of AnnualTimeZoneRule a3 must be 2010 - returned: " + endYear
);
1290 // AnnualTimeZone::getStartInYear
1293 b1
= a1
->getStartInYear(2005, -3*HOUR
, 0, d1
);
1294 b2
= a3
->getStartInYear(2005, -3*HOUR
, 0, d2
);
1295 if (!b1
|| !b2
|| d1
!= d2
) {
1296 errln("FAIL: AnnualTimeZoneRule::getStartInYear did not work as expected");
1298 b2
= a3
->getStartInYear(2015, -3*HOUR
, 0, d2
);
1300 errln("FAIL: AnnualTimeZoneRule::getStartInYear returned TRUE for 2015 which is out of rule range");
1303 // AnnualTimeZone::getFirstStart
1304 b1
= a1
->getFirstStart(-3*HOUR
, 0, d1
);
1305 b2
= a1
->getFirstStart(-4*HOUR
, 1*HOUR
, d2
);
1306 if (!b1
|| !b2
|| d1
!= d2
) {
1307 errln("FAIL: The same start time should be returned by getFirstStart");
1310 // AnnualTimeZone::getFinalStart
1311 b1
= a1
->getFinalStart(-3*HOUR
, 0, d1
);
1313 errln("FAIL: getFinalStart returned TRUE for a1");
1315 b1
= a1
->getStartInYear(2010, -3*HOUR
, 0, d1
);
1316 b2
= a3
->getFinalStart(-3*HOUR
, 0, d2
);
1317 if (!b1
|| !b2
|| d1
!= d2
) {
1318 errln("FAIL: Bad date is returned by getFinalStart");
1321 // AnnualTimeZone::getNextStart / getPreviousStart
1322 b1
= a1
->getNextStart(time1
, -3*HOUR
, 0, FALSE
, d1
);
1324 errln("FAIL: getNextStart returned FALSE for ai");
1326 b2
= a1
->getPreviousStart(d1
, -3*HOUR
, 0, TRUE
, d2
);
1327 if (!b2
|| d1
!= d2
) {
1328 errln("FAIL: Bad Date is returned by getPreviousStart");
1331 b1
= a3
->getNextStart(time2
, -3*HOUR
, 0, FALSE
, d1
);
1333 dataerrln("FAIL: getNextStart must return FALSE when no start time is available after the base time");
1335 b1
= a3
->getFinalStart(-3*HOUR
, 0, d1
);
1336 b2
= a3
->getPreviousStart(time2
, -3*HOUR
, 0, FALSE
, d2
);
1337 if (!b1
|| !b2
|| d1
!= d2
) {
1338 dataerrln("FAIL: getPreviousStart does not match with getFinalStart after the end year");
1341 // AnnualTimeZone::isEquavalentTo
1342 if (!a1
->isEquivalentTo(*a2
)) {
1343 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to a2, but returned FALSE");
1345 if (a1
->isEquivalentTo(*a3
)) {
1346 errln("FAIL: AnnualTimeZoneRule a1 is not equivalent to a3, but returned TRUE");
1348 if (!a1
->isEquivalentTo(*a1
)) {
1349 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to itself, but returned FALSE");
1351 if (a1
->isEquivalentTo(*t1
)) {
1352 errln("FAIL: AnnualTimeZoneRule is not equivalent to TimeArrayTimeZoneRule, but returned TRUE");
1355 // InitialTimezoneRule::operator=/clone
1356 InitialTimeZoneRule
i0("i0", 10*HOUR
, 0);
1357 if (i0
== *i1
|| !(i0
!= *i1
)) {
1358 errln("FAIL: InitialTimeZoneRule i0 is not equal to i1, but got wrong result");
1361 if (i0
!= *i1
|| !(i0
== *i1
)) {
1362 errln("FAIL: InitialTimeZoneRule i0 is equal to i1, but got wrong result");
1364 InitialTimeZoneRule
*i0c
= i0
.clone();
1365 if (*i0c
!= *i1
|| !(*i0c
== *i1
)) {
1366 errln("FAIL: InitialTimeZoneRule i0c is equal to i1, but got wrong result");
1370 // InitialTimeZoneRule::isEquivalentRule
1371 if (!i1
->isEquivalentTo(*i2
)) {
1372 errln("FAIL: InitialTimeZoneRule i1 is equivalent to i2, but returned FALSE");
1374 if (i1
->isEquivalentTo(*i3
)) {
1375 errln("FAIL: InitialTimeZoneRule i1 is not equivalent to i3, but returned TRUE");
1377 if (i1
->isEquivalentTo(*a1
)) {
1378 errln("FAIL: An InitialTimeZoneRule is not equivalent to an AnnualTimeZoneRule, but returned TRUE");
1381 // InitialTimeZoneRule::getFirstStart/getFinalStart/getNextStart/getPreviousStart
1382 b1
= i1
->getFirstStart(0, 0, d1
);
1384 errln("FAIL: InitialTimeZone::getFirstStart returned TRUE");
1386 b1
= i1
->getFinalStart(0, 0, d1
);
1388 errln("FAIL: InitialTimeZone::getFinalStart returned TRUE");
1390 b1
= i1
->getNextStart(time1
, 0, 0, FALSE
, d1
);
1392 errln("FAIL: InitialTimeZone::getNextStart returned TRUE");
1394 b1
= i1
->getPreviousStart(time1
, 0, 0, FALSE
, d1
);
1396 errln("FAIL: InitialTimeZone::getPreviousStart returned TRUE");
1399 // TimeArrayTimeZoneRule::operator=/clone
1400 TimeArrayTimeZoneRule
t0("t0", 4*HOUR
, 0, trtimes1
, 1, DateTimeRule::UTC_TIME
);
1401 if (t0
== *t1
|| !(t0
!= *t1
)) {
1402 errln("FAIL: TimeArrayTimeZoneRule t0 is not equal to t1, but got wrong result");
1405 if (t0
!= *t1
|| !(t0
== *t1
)) {
1406 errln("FAIL: TimeArrayTimeZoneRule t0 is equal to t1, but got wrong result");
1408 TimeArrayTimeZoneRule
*t0c
= t0
.clone();
1409 if (*t0c
!= *t1
|| !(*t0c
== *t1
)) {
1410 errln("FAIL: TimeArrayTimeZoneRule t0c is equal to t1, but got wrong result");
1414 // TimeArrayTimeZoneRule::countStartTimes
1415 if (t1
->countStartTimes() != 1) {
1416 errln("FAIL: Bad start time count is returned by TimeArrayTimeZoneRule::countStartTimes");
1419 // TimeArrayTimeZoneRule::getStartTimeAt
1420 b1
= t1
->getStartTimeAt(-1, d1
);
1422 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned TRUE for index -1");
1424 b1
= t1
->getStartTimeAt(0, d1
);
1425 if (!b1
|| d1
!= trtimes1
[0]) {
1426 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned incorrect result for index 0");
1428 b1
= t1
->getStartTimeAt(1, d1
);
1430 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned TRUE for index 1");
1433 // TimeArrayTimeZoneRule::getTimeType
1434 if (t1
->getTimeType() != DateTimeRule::UTC_TIME
) {
1435 errln("FAIL: TimeArrayTimeZoneRule t1 uses UTC_TIME, but different type is returned");
1437 if (t4
->getTimeType() != DateTimeRule::STANDARD_TIME
) {
1438 errln("FAIL: TimeArrayTimeZoneRule t4 uses STANDARD_TIME, but different type is returned");
1440 if (t5
->getTimeType() != DateTimeRule::WALL_TIME
) {
1441 errln("FAIL: TimeArrayTimeZoneRule t5 uses WALL_TIME, but different type is returned");
1444 // TimeArrayTimeZoneRule::getFirstStart/getFinalStart
1445 b1
= t1
->getFirstStart(0, 0, d1
);
1446 if (!b1
|| d1
!= trtimes1
[0]) {
1447 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t1");
1449 b1
= t1
->getFinalStart(0, 0, d1
);
1450 if (!b1
|| d1
!= trtimes1
[0]) {
1451 errln("FAIL: Bad final start time returned from TimeArrayTimeZoneRule t1");
1453 b1
= t4
->getFirstStart(-4*HOUR
, 1*HOUR
, d1
);
1454 if (!b1
|| d1
!= (trtimes1
[0] + 4*HOUR
)) {
1455 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t4");
1457 b1
= t5
->getFirstStart(-4*HOUR
, 1*HOUR
, d1
);
1458 if (!b1
|| d1
!= (trtimes1
[0] + 3*HOUR
)) {
1459 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t5");
1462 // TimeArrayTimeZoneRule::getNextStart/getPreviousStart
1463 b1
= t3
->getNextStart(time1
, -3*HOUR
, 1*HOUR
, FALSE
, d1
);
1465 dataerrln("FAIL: getNextStart returned TRUE after the final transition for t3");
1467 b1
= t3
->getPreviousStart(time1
, -3*HOUR
, 1*HOUR
, FALSE
, d1
);
1468 if (!b1
|| d1
!= trtimes2
[1]) {
1469 dataerrln("FAIL: Bad start time returned by getPreviousStart for t3");
1471 b2
= t3
->getPreviousStart(d1
, -3*HOUR
, 1*HOUR
, FALSE
, d2
);
1472 if (!b2
|| d2
!= trtimes2
[0]) {
1473 errln("FAIL: Bad start time returned by getPreviousStart for t3");
1476 b1
= t3
->getPreviousStart(time3
, -3*HOUR
, 1*HOUR
, FALSE
, d1
); //time3 - year 1950, no result expected
1478 errln("FAIL: getPreviousStart returned TRUE before the first transition for t3");
1481 // TimeArrayTimeZoneRule::isEquivalentTo
1482 if (!t1
->isEquivalentTo(*t2
)) {
1483 errln("FAIL: TimeArrayTimeZoneRule t1 is equivalent to t2, but returned FALSE");
1485 if (t1
->isEquivalentTo(*t3
)) {
1486 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t3, but returned TRUE");
1488 if (t1
->isEquivalentTo(*t4
)) {
1489 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t4, but returned TRUE");
1491 if (t1
->isEquivalentTo(*a1
)) {
1492 errln("FAIL: TimeArrayTimeZoneRule is not equivalent to AnnualTimeZoneRule, but returned TRUE");
1513 * API coverage test for BasicTimeZone APIs in SimpleTimeZone
1516 TimeZoneRuleTest::TestSimpleTimeZoneCoverage(void) {
1517 UDate time1
= getUTCMillis(1990, UCAL_JUNE
, 1);
1518 UDate time2
= getUTCMillis(2000, UCAL_JUNE
, 1);
1520 TimeZoneTransition tzt1
, tzt2
;
1521 UBool avail1
, avail2
;
1522 UErrorCode status
= U_ZERO_ERROR
;
1523 const TimeZoneRule
*trrules
[2];
1524 const InitialTimeZoneRule
*ir
= NULL
;
1527 // BasicTimeZone API implementation in SimpleTimeZone
1528 SimpleTimeZone
*stz1
= new SimpleTimeZone(-5*HOUR
, "GMT-5");
1530 avail1
= stz1
->getNextTransition(time1
, FALSE
, tzt1
);
1532 errln("FAIL: No transition must be returned by getNextTranstion for SimpleTimeZone with no DST rule");
1534 avail1
= stz1
->getPreviousTransition(time1
, FALSE
, tzt1
);
1536 errln("FAIL: No transition must be returned by getPreviousTransition for SimpleTimeZone with no DST rule");
1539 numTzRules
= stz1
->countTransitionRules(status
);
1540 if (U_FAILURE(status
)) {
1541 errln("FAIL: countTransitionRules failed");
1543 if (numTzRules
!= 0) {
1544 errln((UnicodeString
)"FAIL: countTransitionRules returned " + numTzRules
);
1547 stz1
->getTimeZoneRules(ir
, trrules
, numTzRules
, status
);
1548 if (U_FAILURE(status
)) {
1549 errln("FAIL: getTimeZoneRules failed");
1551 if (numTzRules
!= 0) {
1552 errln("FAIL: Incorrect transition rule count");
1554 if (ir
== NULL
|| ir
->getRawOffset() != stz1
->getRawOffset()) {
1555 errln("FAIL: Bad initial time zone rule");
1559 stz1
->setStartRule(UCAL_MARCH
, 11, 2*HOUR
, status
); // March 11
1560 stz1
->setEndRule(UCAL_NOVEMBER
, 1, UCAL_SUNDAY
, 2*HOUR
, status
); // First Sunday in November
1561 if (U_FAILURE(status
)) {
1562 errln("FAIL: Failed to set DST rules in a SimpleTimeZone");
1565 avail1
= stz1
->getNextTransition(time1
, FALSE
, tzt1
);
1567 errln("FAIL: Non-null transition must be returned by getNextTranstion for SimpleTimeZone with a DST rule");
1569 avail1
= stz1
->getPreviousTransition(time1
, FALSE
, tzt1
);
1571 errln("FAIL: Non-null transition must be returned by getPreviousTransition for SimpleTimeZone with a DST rule");
1574 numTzRules
= stz1
->countTransitionRules(status
);
1575 if (U_FAILURE(status
)) {
1576 errln("FAIL: countTransitionRules failed");
1578 if (numTzRules
!= 2) {
1579 errln((UnicodeString
)"FAIL: countTransitionRules returned " + numTzRules
);
1585 stz1
->getTimeZoneRules(ir
, trrules
, numTzRules
, status
);
1586 if (U_FAILURE(status
)) {
1587 errln("FAIL: getTimeZoneRules failed");
1589 if (numTzRules
!= 2) {
1590 errln("FAIL: Incorrect transition rule count");
1592 if (ir
== NULL
|| ir
->getRawOffset() != stz1
->getRawOffset()) {
1593 errln("FAIL: Bad initial time zone rule");
1595 if (trrules
[0] == NULL
|| trrules
[0]->getRawOffset() != stz1
->getRawOffset()) {
1596 errln("FAIL: Bad transition rule 0");
1598 if (trrules
[1] == NULL
|| trrules
[1]->getRawOffset() != stz1
->getRawOffset()) {
1599 errln("FAIL: Bad transition rule 1");
1602 // Set DST start year
1603 stz1
->setStartYear(2007);
1604 avail1
= stz1
->getPreviousTransition(time1
, FALSE
, tzt1
);
1606 errln("FAIL: No transition must be returned before 1990");
1608 avail1
= stz1
->getNextTransition(time1
, FALSE
, tzt1
); // transition after 1990-06-01
1609 avail2
= stz1
->getNextTransition(time2
, FALSE
, tzt2
); // transition after 2000-06-01
1610 if (!avail1
|| !avail2
|| tzt1
!= tzt2
) {
1611 errln("FAIL: Bad transition returned by SimpleTimeZone::getNextTransition");
1617 * API coverage test for VTimeZone
1620 TimeZoneRuleTest::TestVTimeZoneCoverage(void) {
1621 UErrorCode status
= U_ZERO_ERROR
;
1622 UnicodeString
TZID("Europe/Moscow");
1624 BasicTimeZone
*otz
= (BasicTimeZone
*)TimeZone::createTimeZone(TZID
);
1625 VTimeZone
*vtz
= VTimeZone::createVTimeZoneByID(TZID
);
1627 // getOffset(era, year, month, day, dayOfWeek, milliseconds, ec)
1628 int32_t offset1
= otz
->getOffset(GregorianCalendar::AD
, 2007, UCAL_JULY
, 1, UCAL_SUNDAY
, 0, status
);
1629 if (U_FAILURE(status
)) {
1630 errln("FAIL: getOffset(7 args) failed for otz");
1632 int32_t offset2
= vtz
->getOffset(GregorianCalendar::AD
, 2007, UCAL_JULY
, 1, UCAL_SUNDAY
, 0, status
);
1633 if (U_FAILURE(status
)) {
1634 errln("FAIL: getOffset(7 args) failed for vtz");
1636 if (offset1
!= offset2
) {
1637 errln("FAIL: getOffset(7 args) returned different results in VTimeZone and OlsonTimeZone");
1640 // getOffset(era, year, month, day, dayOfWeek, milliseconds, monthLength, ec)
1641 offset1
= otz
->getOffset(GregorianCalendar::AD
, 2007, UCAL_JULY
, 1, UCAL_SUNDAY
, 0, 31, status
);
1642 if (U_FAILURE(status
)) {
1643 errln("FAIL: getOffset(8 args) failed for otz");
1645 offset2
= vtz
->getOffset(GregorianCalendar::AD
, 2007, UCAL_JULY
, 1, UCAL_SUNDAY
, 0, 31, status
);
1646 if (U_FAILURE(status
)) {
1647 errln("FAIL: getOffset(8 args) failed for vtz");
1649 if (offset1
!= offset2
) {
1650 errln("FAIL: getOffset(8 args) returned different results in VTimeZone and OlsonTimeZone");
1654 // getOffset(date, local, rawOffset, dstOffset, ec)
1655 UDate t
= Calendar::getNow();
1656 int32_t rawOffset1
, dstSavings1
;
1657 int32_t rawOffset2
, dstSavings2
;
1659 otz
->getOffset(t
, FALSE
, rawOffset1
, dstSavings1
, status
);
1660 if (U_FAILURE(status
)) {
1661 errln("FAIL: getOffset(5 args) failed for otz");
1663 vtz
->getOffset(t
, FALSE
, rawOffset2
, dstSavings2
, status
);
1664 if (U_FAILURE(status
)) {
1665 errln("FAIL: getOffset(5 args) failed for vtz");
1667 if (rawOffset1
!= rawOffset2
|| dstSavings1
!= dstSavings2
) {
1668 errln("FAIL: getOffset(long,boolean,int[]) returned different results in VTimeZone and OlsonTimeZone");
1672 if (otz
->getRawOffset() != vtz
->getRawOffset()) {
1673 errln("FAIL: getRawOffset returned different results in VTimeZone and OlsonTimeZone");
1677 UBool inDst1
, inDst2
;
1678 inDst1
= otz
->inDaylightTime(t
, status
);
1679 if (U_FAILURE(status
)) {
1680 dataerrln("FAIL: inDaylightTime failed for otz: %s", u_errorName(status
));
1682 inDst2
= vtz
->inDaylightTime(t
, status
);
1683 if (U_FAILURE(status
)) {
1684 dataerrln("FAIL: inDaylightTime failed for vtz: %s", u_errorName(status
));
1686 if (inDst1
!= inDst2
) {
1687 errln("FAIL: inDaylightTime returned different results in VTimeZone and OlsonTimeZone");
1691 if (otz
->useDaylightTime() != vtz
->useDaylightTime()) {
1692 errln("FAIL: useDaylightTime returned different results in VTimeZone and OlsonTimeZone");
1696 const int32_t RAW
= -10*HOUR
;
1697 VTimeZone
*tmpvtz
= (VTimeZone
*)vtz
->clone();
1698 tmpvtz
->setRawOffset(RAW
);
1699 if (tmpvtz
->getRawOffset() != RAW
) {
1700 logln("setRawOffset is implemented in VTimeZone");
1704 UBool bSame
= otz
->hasSameRules(*vtz
);
1705 logln((UnicodeString
)"OlsonTimeZone::hasSameRules(VTimeZone) should return FALSE always for now - actual: " + bSame
);
1707 // getTZURL/setTZURL
1708 UnicodeString
TZURL("http://icu-project.org/timezone");
1710 if (vtz
->getTZURL(url
)) {
1711 errln("FAIL: getTZURL returned TRUE");
1713 vtz
->setTZURL(TZURL
);
1714 if (!vtz
->getTZURL(url
) || url
!= TZURL
) {
1715 errln("FAIL: URL returned by getTZURL does not match the one set by setTZURL");
1718 // getLastModified/setLastModified
1720 if (vtz
->getLastModified(lastmod
)) {
1721 errln("FAIL: getLastModified returned TRUE");
1723 vtz
->setLastModified(t
);
1724 if (!vtz
->getLastModified(lastmod
) || lastmod
!= t
) {
1725 errln("FAIL: Date returned by getLastModified does not match the one set by setLastModified");
1728 // getNextTransition/getPreviousTransition
1729 UDate base
= getUTCMillis(2007, UCAL_JULY
, 1);
1730 TimeZoneTransition tzt1
, tzt2
;
1731 UBool btr1
= otz
->getNextTransition(base
, TRUE
, tzt1
);
1732 UBool btr2
= vtz
->getNextTransition(base
, TRUE
, tzt2
);
1733 if (!btr1
|| !btr2
|| tzt1
!= tzt2
) {
1734 dataerrln("FAIL: getNextTransition returned different results in VTimeZone and OlsonTimeZone");
1736 btr1
= otz
->getPreviousTransition(base
, FALSE
, tzt1
);
1737 btr2
= vtz
->getPreviousTransition(base
, FALSE
, tzt2
);
1738 if (!btr1
|| !btr2
|| tzt1
!= tzt2
) {
1739 dataerrln("FAIL: getPreviousTransition returned different results in VTimeZone and OlsonTimeZone");
1742 // TimeZoneTransition constructor/clone
1743 TimeZoneTransition
*tzt1c
= tzt1
.clone();
1744 if (*tzt1c
!= tzt1
|| !(*tzt1c
== tzt1
)) {
1745 errln("FAIL: TimeZoneTransition tzt1c is equal to tzt1, but got wrong result");
1748 TimeZoneTransition
tzt3(tzt1
);
1749 if (tzt3
!= tzt1
|| !(tzt3
== tzt1
)) {
1750 errln("FAIL: TimeZoneTransition tzt3 is equal to tzt1, but got wrong result");
1753 // hasEquivalentTransitions
1754 UDate time1
= getUTCMillis(1950, UCAL_JANUARY
, 1);
1755 UDate time2
= getUTCMillis(2020, UCAL_JANUARY
, 1);
1756 UBool equiv
= vtz
->hasEquivalentTransitions(*otz
, time1
, time2
, FALSE
, status
);
1757 if (U_FAILURE(status
)) {
1758 dataerrln("FAIL: hasEquivalentTransitions failed for vtz/otz: %s", u_errorName(status
));
1761 dataerrln("FAIL: hasEquivalentTransitons returned false for the same time zone");
1764 // operator=/operator==/operator!=
1765 VTimeZone
*vtz1
= VTimeZone::createVTimeZoneByID("America/Los_Angeles");
1766 if (*vtz1
== *vtz
|| !(*vtz1
!= *vtz
)) {
1767 errln("FAIL: VTimeZone vtz1 is not equal to vtz, but got wrong result");
1770 if (*vtz1
!= *vtz
|| !(*vtz1
== *vtz
)) {
1771 errln("FAIL: VTimeZone vtz1 is equal to vtz, but got wrong result");
1774 // Creation from BasicTimeZone
1776 status
= U_ZERO_ERROR
;
1777 VTimeZone
*vtzFromBasic
= NULL
;
1778 SimpleTimeZone
*simpleTZ
= new SimpleTimeZone(28800000, "Asia/Singapore");
1779 simpleTZ
->setStartYear(1970);
1780 simpleTZ
->setStartRule(0, // month
1784 simpleTZ
->setEndRule(1, 1, 0, status
);
1785 if (U_FAILURE(status
)) {
1786 errln("File %s, line %d, failed with status = %s", __FILE__
, __LINE__
, u_errorName(status
));
1787 goto end_basic_tz_test
;
1789 vtzFromBasic
= VTimeZone::createVTimeZoneFromBasicTimeZone(*simpleTZ
, status
);
1790 if (U_FAILURE(status
) || vtzFromBasic
== NULL
) {
1791 dataerrln("File %s, line %d, failed with status = %s", __FILE__
, __LINE__
, u_errorName(status
));
1792 goto end_basic_tz_test
;
1795 // delete the source time zone, to make sure there are no dependencies on it.
1798 // Create another simple time zone w the same rules, and check that it is the
1799 // same as the test VTimeZone created above.
1801 SimpleTimeZone
simpleTZ2(28800000, "Asia/Singapore");
1802 simpleTZ2
.setStartYear(1970);
1803 simpleTZ2
.setStartRule(0, // month
1807 simpleTZ2
.setEndRule(1, 1, 0, status
);
1808 if (U_FAILURE(status
)) {
1809 errln("File %s, line %d, failed with status = %s", __FILE__
, __LINE__
, u_errorName(status
));
1810 goto end_basic_tz_test
;
1812 if (vtzFromBasic
->hasSameRules(simpleTZ2
) == FALSE
) {
1813 errln("File %s, line %d, failed hasSameRules() ", __FILE__
, __LINE__
);
1814 goto end_basic_tz_test
;
1818 delete vtzFromBasic
;
1828 TimeZoneRuleTest::TestVTimeZoneParse(void) {
1829 UErrorCode status
= U_ZERO_ERROR
;
1831 // Trying to create VTimeZone from empty data
1832 UnicodeString emptyData
;
1833 VTimeZone
*empty
= VTimeZone::createVTimeZone(emptyData
, status
);
1834 if (U_SUCCESS(status
) || empty
!= NULL
) {
1836 errln("FAIL: Non-null VTimeZone is returned for empty VTIMEZONE data");
1838 status
= U_ZERO_ERROR
;
1840 // Create VTimeZone for Asia/Tokyo
1841 UnicodeString
asiaTokyoID("Asia/Tokyo");
1842 static const UChar asiaTokyo
[] = {
1843 /* "BEGIN:VTIMEZONE\x0D\x0A" */
1844 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
1845 /* "TZID:Asia\x0D\x0A" */
1846 0x54,0x5A,0x49,0x44,0x3A,0x41,0x73,0x69,0x61,0x0D,0x0A,
1847 /* "\x09/Tokyo\x0D\x0A" */
1848 0x09,0x2F,0x54,0x6F,0x6B,0x79,0x6F,0x0D,0x0A,
1849 /* "BEGIN:STANDARD\x0D\x0A" */
1850 0x42,0x45,0x47,0x49,0x4E,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1851 /* "TZOFFSETFROM:+0900\x0D\x0A" */
1852 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2B,0x30,0x39,0x30,0x30,0x0D,0x0A,
1853 /* "TZOFFSETTO:+0900\x0D\x0A" */
1854 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2B,0x30,0x39,0x30,0x30,0x0D,0x0A,
1855 /* "TZNAME:JST\x0D\x0A" */
1856 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x4A,0x53,0x54,0x0D,0x0A,
1857 /* "DTSTART:19700101\x0D\x0A" */
1858 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3A,0x31,0x39,0x37,0x30,0x30,0x31,0x30,0x31,0x0D,0x0A,
1859 /* " T000000\x0D\x0A" */
1860 0x20,0x54,0x30,0x30,0x30,0x30,0x30,0x30,0x0D,0x0A,
1861 /* "END:STANDARD\x0D\x0A" */
1862 0x45,0x4E,0x44,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1863 /* "END:VTIMEZONE" */
1864 0x45,0x4E,0x44,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,
1867 VTimeZone
*tokyo
= VTimeZone::createVTimeZone(asiaTokyo
, status
);
1868 if (U_FAILURE(status
) || tokyo
== NULL
) {
1869 errln("FAIL: Failed to create a VTimeZone tokyo");
1874 if (tzid
!= asiaTokyoID
) {
1875 errln((UnicodeString
)"FAIL: Invalid TZID: " + tzid
);
1877 // Make sure offsets are correct
1878 int32_t rawOffset
, dstSavings
;
1879 tokyo
->getOffset(Calendar::getNow(), FALSE
, rawOffset
, dstSavings
, status
);
1880 if (U_FAILURE(status
)) {
1881 errln("FAIL: getOffset failed for tokyo");
1883 if (rawOffset
!= 9*HOUR
|| dstSavings
!= 0) {
1884 errln("FAIL: Bad offsets returned by a VTimeZone created for Tokyo");
1889 // Create VTimeZone from VTIMEZONE data
1890 static const UChar fooData
[] = {
1891 /* "BEGIN:VCALENDAR\x0D\x0A" */
1892 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x43,0x41,0x4C,0x45,0x4E,0x44,0x41,0x52,0x0D,0x0A,
1893 /* "BEGIN:VTIMEZONE\x0D\x0A" */
1894 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
1895 /* "TZID:FOO\x0D\x0A" */
1896 0x54,0x5A,0x49,0x44,0x3A,0x46,0x4F,0x4F,0x0D,0x0A,
1897 /* "BEGIN:STANDARD\x0D\x0A" */
1898 0x42,0x45,0x47,0x49,0x4E,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1899 /* "TZOFFSETFROM:-0700\x0D\x0A" */
1900 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2D,0x30,0x37,0x30,0x30,0x0D,0x0A,
1901 /* "TZOFFSETTO:-0800\x0D\x0A" */
1902 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2D,0x30,0x38,0x30,0x30,0x0D,0x0A,
1903 /* "TZNAME:FST\x0D\x0A" */
1904 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x46,0x53,0x54,0x0D,0x0A,
1905 /* "DTSTART:20071010T010000\x0D\x0A" */
1906 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,
1907 /* "RRULE:FREQ=YEARLY;BYDAY=WE;BYMONTHDAY=10,11,12,13,14,15,16;BYMONTH=10\x0D\x0A" */
1908 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,
1909 /* "END:STANDARD\x0D\x0A" */
1910 0x45,0x4E,0x44,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1911 /* "BEGIN:DAYLIGHT\x0D\x0A" */
1912 0x42,0x45,0x47,0x49,0x4E,0x3A,0x44,0x41,0x59,0x4C,0x49,0x47,0x48,0x54,0x0D,0x0A,
1913 /* "TZOFFSETFROM:-0800\x0D\x0A" */
1914 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2D,0x30,0x38,0x30,0x30,0x0D,0x0A,
1915 /* "TZOFFSETTO:-0700\x0D\x0A" */
1916 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2D,0x30,0x37,0x30,0x30,0x0D,0x0A,
1917 /* "TZNAME:FDT\x0D\x0A" */
1918 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x46,0x44,0x54,0x0D,0x0A,
1919 /* "DTSTART:20070415T010000\x0D\x0A" */
1920 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,
1921 /* "RRULE:FREQ=YEARLY;BYMONTHDAY=15;BYMONTH=4\x0D\x0A" */
1922 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,
1923 /* "END:DAYLIGHT\x0D\x0A" */
1924 0x45,0x4E,0x44,0x3A,0x44,0x41,0x59,0x4C,0x49,0x47,0x48,0x54,0x0D,0x0A,
1925 /* "END:VTIMEZONE\x0D\x0A" */
1926 0x45,0x4E,0x44,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
1927 /* "END:VCALENDAR" */
1928 0x45,0x4E,0x44,0x3A,0x56,0x43,0x41,0x4C,0x45,0x4E,0x44,0x41,0x52,
1932 VTimeZone
*foo
= VTimeZone::createVTimeZone(fooData
, status
);
1933 if (U_FAILURE(status
) || foo
== NULL
) {
1934 errln("FAIL: Failed to create a VTimeZone foo");
1936 // Write VTIMEZONE data
1937 UnicodeString fooData2
;
1938 foo
->write(getUTCMillis(2005, UCAL_JANUARY
, 1), fooData2
, status
);
1939 if (U_FAILURE(status
)) {
1940 errln("FAIL: Failed to write VTIMEZONE data for foo");
1948 TimeZoneRuleTest::TestT6216(void) {
1949 // Test case in #6216
1950 static const UChar tokyoTZ
[] = {
1951 /* "BEGIN:VCALENDAR\r\n" */
1952 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
1953 /* "VERSION:2.0\r\n" */
1954 0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x3a,0x32,0x2e,0x30,0x0d,0x0a,
1955 /* "PRODID:-//PYVOBJECT//NONSGML Version 1//EN\r\n" */
1956 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,
1957 /* "BEGIN:VTIMEZONE\r\n" */
1958 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
1959 /* "TZID:Asia/Tokyo\r\n" */
1960 0x54,0x5a,0x49,0x44,0x3a,0x41,0x73,0x69,0x61,0x2f,0x54,0x6f,0x6b,0x79,0x6f,0x0d,0x0a,
1961 /* "BEGIN:STANDARD\r\n" */
1962 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
1963 /* "DTSTART:20000101T000000\r\n" */
1964 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,
1965 /* "RRULE:FREQ=YEARLY;BYMONTH=1\r\n" */
1966 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,
1967 /* "TZNAME:Asia/Tokyo\r\n" */
1968 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x41,0x73,0x69,0x61,0x2f,0x54,0x6f,0x6b,0x79,0x6f,0x0d,0x0a,
1969 /* "TZOFFSETFROM:+0900\r\n" */
1970 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2b,0x30,0x39,0x30,0x30,0x0d,0x0a,
1971 /* "TZOFFSETTO:+0900\r\n" */
1972 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2b,0x30,0x39,0x30,0x30,0x0d,0x0a,
1973 /* "END:STANDARD\r\n" */
1974 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
1975 /* "END:VTIMEZONE\r\n" */
1976 0x45,0x4e,0x44,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
1977 /* "END:VCALENDAR" */
1978 0x45,0x4e,0x44,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
1981 // Single final rule, overlapping with another
1982 static const UChar finalOverlap
[] = {
1983 /* "BEGIN:VCALENDAR\r\n" */
1984 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
1985 /* "BEGIN:VTIMEZONE\r\n" */
1986 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
1987 /* "TZID:FinalOverlap\r\n" */
1988 0x54,0x5a,0x49,0x44,0x3a,0x46,0x69,0x6e,0x61,0x6c,0x4f,0x76,0x65,0x72,0x6c,0x61,0x70,0x0d,0x0a,
1989 /* "BEGIN:STANDARD\r\n" */
1990 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
1991 /* "TZOFFSETFROM:-0200\r\n" */
1992 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a,
1993 /* "TZOFFSETTO:-0300\r\n" */
1994 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a,
1995 /* "TZNAME:STD\r\n" */
1996 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x53,0x54,0x44,0x0d,0x0a,
1997 /* "DTSTART:20001029T020000\r\n" */
1998 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,
1999 /* "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" */
2000 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,
2001 /* "END:STANDARD\r\n" */
2002 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
2003 /* "BEGIN:DAYLIGHT\r\n" */
2004 0x42,0x45,0x47,0x49,0x4e,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a,
2005 /* "TZOFFSETFROM:-0300\r\n" */
2006 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a,
2007 /* "TZOFFSETTO:-0200\r\n" */
2008 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a,
2009 /* "TZNAME:DST\r\n" */
2010 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x44,0x53,0x54,0x0d,0x0a,
2011 /* "DTSTART:19990404T020000\r\n" */
2012 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,
2013 /* "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" */
2014 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,
2015 /* "END:DAYLIGHT\r\n" */
2016 0x45,0x4e,0x44,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a,
2017 /* "END:VTIMEZONE\r\n" */
2018 0x45,0x4e,0x44,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
2019 /* "END:VCALENDAR" */
2020 0x45,0x4e,0x44,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
2023 // Single final rule, no overlapping with another
2024 static const UChar finalNonOverlap
[] = {
2025 /* "BEGIN:VCALENDAR\r\n" */
2026 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
2027 /* "BEGIN:VTIMEZONE\r\n" */
2028 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
2029 /* "TZID:FinalNonOverlap\r\n" */
2030 0x54,0x5a,0x49,0x44,0x3a,0x46,0x69,0x6e,0x61,0x6c,0x4e,0x6f,0x6e,0x4f,0x76,0x65,0x72,0x6c,0x61,0x70,0x0d,0x0a,
2031 /* "BEGIN:STANDARD\r\n" */
2032 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
2033 /* "TZOFFSETFROM:-0200\r\n" */
2034 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a,
2035 /* "TZOFFSETTO:-0300\r\n" */
2036 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a,
2037 /* "TZNAME:STD\r\n" */
2038 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x53,0x54,0x44,0x0d,0x0a,
2039 /* "DTSTART:20001029T020000\r\n" */
2040 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,
2041 /* "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10;UNTIL=20041031T040000Z\r\n" */
2042 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,
2043 /* "END:STANDARD\r\n" */
2044 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
2045 /* "BEGIN:DAYLIGHT\r\n" */
2046 0x42,0x45,0x47,0x49,0x4e,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a,
2047 /* "TZOFFSETFROM:-0300\r\n" */
2048 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a,
2049 /* "TZOFFSETTO:-0200\r\n" */
2050 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a,
2051 /* "TZNAME:DST\r\n" */
2052 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x44,0x53,0x54,0x0d,0x0a,
2053 /* "DTSTART:19990404T020000\r\n" */
2054 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,
2055 /* "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" */
2056 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,
2057 /* "END:DAYLIGHT\r\n" */
2058 0x45,0x4e,0x44,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a,
2059 /* "BEGIN:STANDARD\r\n" */
2060 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
2061 /* "TZOFFSETFROM:-0200\r\n" */
2062 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a,
2063 /* "TZOFFSETTO:-0300\r\n" */
2064 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a,
2065 /* "TZNAME:STDFINAL\r\n" */
2066 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x53,0x54,0x44,0x46,0x49,0x4e,0x41,0x4c,0x0d,0x0a,
2067 /* "DTSTART:20071028T020000\r\n" */
2068 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,
2069 /* "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" */
2070 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,
2071 /* "END:STANDARD\r\n" */
2072 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
2073 /* "END:VTIMEZONE\r\n" */
2074 0x45,0x4e,0x44,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
2075 /* "END:VCALENDAR" */
2076 0x45,0x4e,0x44,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
2080 static const int32_t TestDates
[][3] = {
2081 {1995, UCAL_JANUARY
, 1},
2082 {1995, UCAL_JULY
, 1},
2083 {2000, UCAL_JANUARY
, 1},
2084 {2000, UCAL_JULY
, 1},
2085 {2005, UCAL_JANUARY
, 1},
2086 {2005, UCAL_JULY
, 1},
2087 {2010, UCAL_JANUARY
, 1},
2088 {2010, UCAL_JULY
, 1},
2092 /*static*/ const UnicodeString TestZones
[] = {
2093 UnicodeString(tokyoTZ
),
2094 UnicodeString(finalOverlap
),
2095 UnicodeString(finalNonOverlap
),
2099 int32_t Expected
[][8] = {
2100 // JAN90 JUL90 JAN00 JUL00 JAN05 JUL05 JAN10 JUL10
2101 { 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000},
2102 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000},
2103 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000}
2109 UDate times
[sizeof(TestDates
) / (3 * sizeof(int32_t))];
2112 UErrorCode status
= U_ZERO_ERROR
;
2113 TimeZone
*utc
= TimeZone::createTimeZone("Etc/GMT");
2114 GregorianCalendar
cal(utc
, status
);
2115 if (U_FAILURE(status
)) {
2116 dataerrln("FAIL: Failed to creat a GregorianCalendar: %s", u_errorName(status
));
2119 for (i
= 0; TestDates
[i
][2] != 0; i
++) {
2121 cal
.set(TestDates
[i
][0], TestDates
[i
][1], TestDates
[i
][2]);
2122 times
[i
] = cal
.getTime(status
);
2123 if (U_FAILURE(status
)) {
2124 errln("FAIL: getTime failed");
2131 for (i
= 0; !TestZones
[i
].isEmpty(); i
++) {
2132 VTimeZone
*vtz
= VTimeZone::createVTimeZone(TestZones
[i
], status
);
2133 if (U_FAILURE(status
)) {
2134 errln("FAIL: failed to create VTimeZone");
2137 for (j
= 0; j
< numTimes
; j
++) {
2139 status
= U_ZERO_ERROR
;
2140 vtz
->getOffset(times
[j
], FALSE
, raw
, dst
, status
);
2141 if (U_FAILURE(status
)) {
2142 errln((UnicodeString
)"FAIL: getOffset failed for time zone " + i
+ " at " + times
[j
]);
2144 int32_t offset
= raw
+ dst
;
2145 if (offset
!= Expected
[i
][j
]) {
2146 errln((UnicodeString
)"FAIL: Invalid offset at time(" + times
[j
] + "):" + offset
+ " Expected:" + Expected
[i
][j
]);
2154 TimeZoneRuleTest::TestT6669(void) {
2155 UErrorCode status
= U_ZERO_ERROR
;
2156 SimpleTimeZone
stz(0, "CustomID", UCAL_JANUARY
, 1, UCAL_SUNDAY
, 0, UCAL_JULY
, 1, UCAL_SUNDAY
, 0, status
);
2157 if (U_FAILURE(status
)) {
2158 errln("FAIL: Failed to creat a SimpleTimeZone");
2162 UDate t
= 1230681600000.0; //2008-12-31T00:00:00
2163 UDate expectedNext
= 1231027200000.0; //2009-01-04T00:00:00
2164 UDate expectedPrev
= 1215298800000.0; //2008-07-06T00:00:00
2166 TimeZoneTransition tzt
;
2167 UBool avail
= stz
.getNextTransition(t
, FALSE
, tzt
);
2169 errln("FAIL: No transition returned by getNextTransition.");
2170 } else if (tzt
.getTime() != expectedNext
) {
2171 errln((UnicodeString
)"FAIL: Wrong transition time returned by getNextTransition - "
2172 + tzt
.getTime() + " Expected: " + expectedNext
);
2175 avail
= stz
.getPreviousTransition(t
, TRUE
, tzt
);
2177 errln("FAIL: No transition returned by getPreviousTransition.");
2178 } else if (tzt
.getTime() != expectedPrev
) {
2179 errln((UnicodeString
)"FAIL: Wrong transition time returned by getPreviousTransition - "
2180 + tzt
.getTime() + " Expected: " + expectedPrev
);
2185 TimeZoneRuleTest::TestVTimeZoneWrapper(void) {
2189 UChar
* data
= NULL
;
2193 UDate base
= 1231027200000.0; //2009-01-04T00:00:00
2196 const char *name
= "Test Initial";
2210 uprv_memset(uname
, 0, sizeof(uname
));
2211 u_uastrcpy(uname
, name
);
2214 ir1
= izrule_open(uname
, 13, 2*HOUR
, 0);
2215 ir2
= izrule_clone(ir1
);
2218 b
= izrule_equals(ir1
, ir2
);
2219 b
= izrule_isEquivalentTo(ir1
, ir2
);
2222 izrule_getName(ir1
, data
, length
);
2223 i
= izrule_getRawOffset(ir1
);
2224 i
= izrule_getDSTSavings(ir1
);
2226 b
= izrule_getFirstStart(ir1
, 2*HOUR
, 0, result
);
2227 b
= izrule_getFinalStart(ir1
, 2*HOUR
, 0, result
);
2228 b
= izrule_getNextStart(ir1
, base
, 2*HOUR
, 0, true, result
);
2229 b
= izrule_getPreviousStart(ir1
, base
, 2*HOUR
, 0, true, result
);
2232 cid1
= izrule_getStaticClassID(ir1
);
2233 cid2
= izrule_getDynamicClassID(ir1
);
2236 zt1
= ztrans_open(base
, ir1
, ir2
);
2237 zt2
= ztrans_clone(zt1
);
2238 zt2
= ztrans_openEmpty();
2241 b
= ztrans_equals(zt1
, zt2
);
2244 result
= ztrans_getTime(zt1
);
2245 ztrans_setTime(zt1
, result
);
2247 r
= (ZRule
*)ztrans_getFrom(zt1
);
2248 ztrans_setFrom(zt1
, (void*)ir1
);
2249 ztrans_adoptFrom(zt1
, (void*)ir1
);
2251 r
= (ZRule
*)ztrans_getTo(zt1
);
2252 ztrans_setTo(zt1
, (void*)ir2
);
2253 ztrans_adoptTo(zt1
, (void*)ir2
);
2256 cid1
= ztrans_getStaticClassID(zt1
);
2257 cid2
= ztrans_getDynamicClassID(zt2
);
2260 v1
= vzone_openID((UChar
*)"America/Chicago", sizeof("America/Chicago"));
2261 v2
= vzone_clone(v1
);
2262 //v2 = vzone_openData(const UChar* vtzdata, int32_t vtzdataLength, UErrorCode& status);
2265 b
= vzone_equals(v1
, v2
);
2266 b
= vzone_hasSameRules(v1
, v2
);
2269 b
= vzone_getTZURL(v1
, data
, length
);
2270 vzone_setTZURL(v1
, data
, length
);
2272 b
= vzone_getLastModified(v1
, result
);
2273 vzone_setLastModified(v1
, result
);
2276 vzone_write(v1
, data
, length
, status
);
2277 vzone_writeFromStart(v1
, result
, data
, length
, status
);
2278 vzone_writeSimple(v1
, result
, data
, length
, status
);
2280 // test more accessors
2281 i
= vzone_getRawOffset(v1
);
2282 vzone_setRawOffset(v1
, i
);
2284 b
= vzone_useDaylightTime(v1
);
2285 b
= vzone_inDaylightTime(v1
, result
, status
);
2287 b
= vzone_getNextTransition(v1
, result
, false, zt1
);
2288 b
= vzone_getPreviousTransition(v1
, result
, false, zt1
);
2289 i
= vzone_countTransitionRules(v1
, status
);
2291 cid1
= vzone_getStaticClassID(v1
);
2292 cid2
= vzone_getDynamicClassID(v1
);
2302 //----------- private test helpers -------------------------------------------------
2305 TimeZoneRuleTest::getUTCMillis(int32_t y
, int32_t m
, int32_t d
,
2306 int32_t hr
, int32_t min
, int32_t sec
, int32_t msec
) {
2307 UErrorCode status
= U_ZERO_ERROR
;
2308 const TimeZone
*tz
= TimeZone::getGMT();
2309 Calendar
*cal
= Calendar::createInstance(*tz
, status
);
2310 if (U_FAILURE(status
)) {
2312 dataerrln("FAIL: Calendar::createInstance failed: %s", u_errorName(status
));
2315 cal
->set(y
, m
, d
, hr
, min
, sec
);
2316 cal
->set(UCAL_MILLISECOND
, msec
);
2317 UDate utc
= cal
->getTime(status
);
2318 if (U_FAILURE(status
)) {
2320 errln("FAIL: Calendar::getTime failed");
2328 * Check if a time shift really happens on each transition returned by getNextTransition or
2329 * getPreviousTransition in the specified time range
2332 TimeZoneRuleTest::verifyTransitions(BasicTimeZone
& icutz
, UDate start
, UDate end
) {
2333 UErrorCode status
= U_ZERO_ERROR
;
2335 int32_t raw
, dst
, raw0
, dst0
;
2336 TimeZoneTransition tzt
, tzt0
;
2344 avail
= icutz
.getNextTransition(time
, FALSE
, tzt
);
2348 time
= tzt
.getTime();
2352 icutz
.getOffset(time
, FALSE
, raw
, dst
, status
);
2353 icutz
.getOffset(time
- 1, FALSE
, raw0
, dst0
, status
);
2354 if (U_FAILURE(status
)) {
2355 errln("FAIL: Error in getOffset");
2359 if (raw
== raw0
&& dst
== dst0
) {
2360 errln((UnicodeString
)"FAIL: False transition returned by getNextTransition for "
2361 + icutz
.getID(tzid
) + " at " + dateToString(time
));
2364 (tzt0
.getTo()->getRawOffset() != tzt
.getFrom()->getRawOffset()
2365 || tzt0
.getTo()->getDSTSavings() != tzt
.getFrom()->getDSTSavings())) {
2366 errln((UnicodeString
)"FAIL: TO rule of the previous transition does not match FROM rule of this transtion at "
2367 + dateToString(time
) + " for " + icutz
.getID(tzid
));
2377 avail
= icutz
.getPreviousTransition(time
, FALSE
, tzt
);
2381 time
= tzt
.getTime();
2382 if (time
<= start
) {
2385 icutz
.getOffset(time
, FALSE
, raw
, dst
, status
);
2386 icutz
.getOffset(time
- 1, FALSE
, raw0
, dst0
, status
);
2387 if (U_FAILURE(status
)) {
2388 errln("FAIL: Error in getOffset");
2392 if (raw
== raw0
&& dst
== dst0
) {
2393 errln((UnicodeString
)"FAIL: False transition returned by getPreviousTransition for "
2394 + icutz
.getID(tzid
) + " at " + dateToString(time
));
2398 (tzt0
.getFrom()->getRawOffset() != tzt
.getTo()->getRawOffset()
2399 || tzt0
.getFrom()->getDSTSavings() != tzt
.getTo()->getDSTSavings())) {
2400 errln((UnicodeString
)"FAIL: TO rule of the next transition does not match FROM rule in this transtion at "
2401 + dateToString(time
) + " for " + icutz
.getID(tzid
));
2409 * Compare all time transitions in 2 time zones in the specified time range in ascending order
2412 TimeZoneRuleTest::compareTransitionsAscending(BasicTimeZone
& z1
, BasicTimeZone
& z2
,
2413 UDate start
, UDate end
, UBool inclusive
) {
2414 UnicodeString zid1
, zid2
;
2415 TimeZoneTransition tzt1
, tzt2
;
2416 UBool avail1
, avail2
;
2417 UBool inRange1
, inRange2
;
2424 avail1
= z1
.getNextTransition(time
, inclusive
, tzt1
);
2425 avail2
= z2
.getNextTransition(time
, inclusive
, tzt2
);
2427 inRange1
= inRange2
= FALSE
;
2429 if (tzt1
.getTime() < end
|| (inclusive
&& tzt1
.getTime() == end
)) {
2434 if (tzt2
.getTime() < end
|| (inclusive
&& tzt2
.getTime() == end
)) {
2438 if (!inRange1
&& !inRange2
) {
2439 // No more transition in the range
2443 errln((UnicodeString
)"FAIL: " + zid1
+ " does not have any transitions after "
2444 + dateToString(time
) + " before " + dateToString(end
));
2448 errln((UnicodeString
)"FAIL: " + zid2
+ " does not have any transitions after "
2449 + dateToString(time
) + " before " + dateToString(end
));
2452 if (tzt1
.getTime() != tzt2
.getTime()) {
2453 errln((UnicodeString
)"FAIL: First transition after " + dateToString(time
) + " "
2454 + zid1
+ "[" + dateToString(tzt1
.getTime()) + "] "
2455 + zid2
+ "[" + dateToString(tzt2
.getTime()) + "]");
2458 time
= tzt1
.getTime();
2466 * Compare all time transitions in 2 time zones in the specified time range in descending order
2469 TimeZoneRuleTest::compareTransitionsDescending(BasicTimeZone
& z1
, BasicTimeZone
& z2
,
2470 UDate start
, UDate end
, UBool inclusive
) {
2471 UnicodeString zid1
, zid2
;
2472 TimeZoneTransition tzt1
, tzt2
;
2473 UBool avail1
, avail2
;
2474 UBool inRange1
, inRange2
;
2481 avail1
= z1
.getPreviousTransition(time
, inclusive
, tzt1
);
2482 avail2
= z2
.getPreviousTransition(time
, inclusive
, tzt2
);
2484 inRange1
= inRange2
= FALSE
;
2486 if (tzt1
.getTime() > start
|| (inclusive
&& tzt1
.getTime() == start
)) {
2491 if (tzt2
.getTime() > start
|| (inclusive
&& tzt2
.getTime() == start
)) {
2495 if (!inRange1
&& !inRange2
) {
2496 // No more transition in the range
2500 errln((UnicodeString
)"FAIL: " + zid1
+ " does not have any transitions before "
2501 + dateToString(time
) + " after " + dateToString(start
));
2505 errln((UnicodeString
)"FAIL: " + zid2
+ " does not have any transitions before "
2506 + dateToString(time
) + " after " + dateToString(start
));
2509 if (tzt1
.getTime() != tzt2
.getTime()) {
2510 errln((UnicodeString
)"FAIL: Last transition before " + dateToString(time
) + " "
2511 + zid1
+ "[" + dateToString(tzt1
.getTime()) + "] "
2512 + zid2
+ "[" + dateToString(tzt2
.getTime()) + "]");
2515 time
= tzt1
.getTime();
2522 // Slightly modified version of BasicTimeZone::hasEquivalentTransitions.
2523 // This version returns TRUE if transition time delta is within the given
2525 static UBool
hasEquivalentTransitions(/*const*/ BasicTimeZone
& tz1
, /*const*/BasicTimeZone
& tz2
,
2526 UDate start
, UDate end
,
2527 UBool ignoreDstAmount
, int32_t maxTransitionTimeDelta
,
2528 UErrorCode
& status
) {
2529 if (U_FAILURE(status
)) {
2532 if (tz1
.hasSameRules(tz2
)) {
2535 // Check the offsets at the start time
2536 int32_t raw1
, raw2
, dst1
, dst2
;
2537 tz1
.getOffset(start
, FALSE
, raw1
, dst1
, status
);
2538 if (U_FAILURE(status
)) {
2541 tz2
.getOffset(start
, FALSE
, raw2
, dst2
, status
);
2542 if (U_FAILURE(status
)) {
2545 if (ignoreDstAmount
) {
2546 if ((raw1
+ dst1
!= raw2
+ dst2
)
2547 || (dst1
!= 0 && dst2
== 0)
2548 || (dst1
== 0 && dst2
!= 0)) {
2552 if (raw1
!= raw2
|| dst1
!= dst2
) {
2556 // Check transitions in the range
2558 TimeZoneTransition tr1
, tr2
;
2560 UBool avail1
= tz1
.getNextTransition(time
, FALSE
, tr1
);
2561 UBool avail2
= tz2
.getNextTransition(time
, FALSE
, tr2
);
2563 if (ignoreDstAmount
) {
2564 // Skip a transition which only differ the amount of DST savings
2567 && tr1
.getTime() <= end
2568 && (tr1
.getFrom()->getRawOffset() + tr1
.getFrom()->getDSTSavings()
2569 == tr1
.getTo()->getRawOffset() + tr1
.getTo()->getDSTSavings())
2570 && (tr1
.getFrom()->getDSTSavings() != 0 && tr1
.getTo()->getDSTSavings() != 0)) {
2571 tz1
.getNextTransition(tr1
.getTime(), FALSE
, tr1
);
2578 && tr2
.getTime() <= end
2579 && (tr2
.getFrom()->getRawOffset() + tr2
.getFrom()->getDSTSavings()
2580 == tr2
.getTo()->getRawOffset() + tr2
.getTo()->getDSTSavings())
2581 && (tr2
.getFrom()->getDSTSavings() != 0 && tr2
.getTo()->getDSTSavings() != 0)) {
2582 tz2
.getNextTransition(tr2
.getTime(), FALSE
, tr2
);
2589 UBool inRange1
= (avail1
&& tr1
.getTime() <= end
);
2590 UBool inRange2
= (avail2
&& tr2
.getTime() <= end
);
2591 if (!inRange1
&& !inRange2
) {
2592 // No more transition in the range
2595 if (!inRange1
|| !inRange2
) {
2598 double delta
= tr1
.getTime() >= tr2
.getTime() ? tr1
.getTime() - tr2
.getTime() : tr2
.getTime() - tr1
.getTime();
2599 if (delta
> (double)maxTransitionTimeDelta
) {
2602 if (ignoreDstAmount
) {
2603 if (tr1
.getTo()->getRawOffset() + tr1
.getTo()->getDSTSavings()
2604 != tr2
.getTo()->getRawOffset() + tr2
.getTo()->getDSTSavings()
2605 || (tr1
.getTo()->getDSTSavings() != 0 && tr2
.getTo()->getDSTSavings() == 0)
2606 || (tr1
.getTo()->getDSTSavings() == 0 && tr2
.getTo()->getDSTSavings() != 0)) {
2610 if (tr1
.getTo()->getRawOffset() != tr2
.getTo()->getRawOffset() ||
2611 tr1
.getTo()->getDSTSavings() != tr2
.getTo()->getDSTSavings()) {
2615 time
= tr1
.getTime() > tr2
.getTime() ? tr1
.getTime() : tr2
.getTime();
2620 // Test case for ticket#8943
2621 // RuleBasedTimeZone#getOffsets throws NPE
2623 TimeZoneRuleTest::TestT8943(void) {
2624 UErrorCode status
= U_ZERO_ERROR
;
2625 UnicodeString
id("Ekaterinburg Time");
2626 UnicodeString
stdName("Ekaterinburg Standard Time");
2627 UnicodeString
dstName("Ekaterinburg Daylight Time");
2629 InitialTimeZoneRule
*initialRule
= new InitialTimeZoneRule(stdName
, 18000000, 0);
2630 RuleBasedTimeZone
*rbtz
= new RuleBasedTimeZone(id
, initialRule
);
2632 DateTimeRule
*dtRule
= new DateTimeRule(UCAL_OCTOBER
, -1, UCAL_SUNDAY
, 10800000, DateTimeRule::WALL_TIME
);
2633 AnnualTimeZoneRule
*atzRule
= new AnnualTimeZoneRule(stdName
, 18000000, 0, dtRule
, 2000, 2010);
2634 rbtz
->addTransitionRule(atzRule
, status
);
2636 dtRule
= new DateTimeRule(UCAL_MARCH
, -1, UCAL_SUNDAY
, 7200000, DateTimeRule::WALL_TIME
);
2637 atzRule
= new AnnualTimeZoneRule(dstName
, 18000000, 3600000, dtRule
, 2000, 2010);
2638 rbtz
->addTransitionRule(atzRule
, status
);
2640 dtRule
= new DateTimeRule(UCAL_JANUARY
, 1, 0, DateTimeRule::WALL_TIME
);
2641 atzRule
= new AnnualTimeZoneRule(stdName
, 21600000, 0, dtRule
, 2011, AnnualTimeZoneRule::MAX_YEAR
);
2642 rbtz
->addTransitionRule(atzRule
, status
);
2644 dtRule
= new DateTimeRule(UCAL_JANUARY
, 1, 1, DateTimeRule::WALL_TIME
);
2645 atzRule
= new AnnualTimeZoneRule(dstName
, 21600000, 0, dtRule
, 2011, AnnualTimeZoneRule::MAX_YEAR
);
2646 rbtz
->addTransitionRule(atzRule
, status
);
2647 rbtz
->complete(status
);
2649 if (U_FAILURE(status
)) {
2650 errln("Failed to construct a RuleBasedTimeZone");
2653 rbtz
->getOffset(1293822000000.0 /* 2010-12-31 19:00:00 UTC */, FALSE
, raw
, dst
, status
);
2654 if (U_FAILURE(status
)) {
2655 errln("Error invoking getOffset");
2656 } else if (raw
!= 21600000 || dst
!= 0) {
2657 errln(UnicodeString("Fail: Wrong offsets: ") + raw
+ "/" + dst
+ " Expected: 21600000/0");
2664 #endif /* #if !UCONFIG_NO_FORMATTING */