1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2007-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
10 #include "unicode/utypes.h"
12 #if !UCONFIG_NO_FORMATTING
14 #include "unicode/dtrule.h"
15 #include "unicode/tzrule.h"
16 #include "unicode/rbtz.h"
17 #include "unicode/simpletz.h"
18 #include "unicode/tzrule.h"
19 #include "unicode/calendar.h"
20 #include "unicode/gregocal.h"
21 #include "unicode/strenum.h"
22 #include "unicode/ucal.h"
23 #include "unicode/unistr.h"
24 #include "unicode/ustring.h"
25 #include "unicode/tztrans.h"
26 #include "unicode/vtzone.h"
33 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
34 #define HOUR (60*60*1000)
36 static const char *const TESTZIDS
[] = {
39 "America/Los_Angeles",
40 "America/Indiana/Indianapolis",
52 static UBool
hasEquivalentTransitions(/*const*/ BasicTimeZone
& tz1
, /*const*/BasicTimeZone
& tz2
,
53 UDate start
, UDate end
,
54 UBool ignoreDstAmount
, int32_t maxTransitionTimeDelta
,
57 class TestZIDEnumeration
: public StringEnumeration
{
59 TestZIDEnumeration(UBool all
= FALSE
);
60 ~TestZIDEnumeration();
62 virtual int32_t count(UErrorCode
& /*status*/) const {
65 virtual const UnicodeString
*snext(UErrorCode
& status
);
66 virtual void reset(UErrorCode
& status
);
67 static inline UClassID
getStaticClassID() {
68 return (UClassID
)&fgClassID
;
70 virtual UClassID
getDynamicClassID() const {
71 return getStaticClassID();
74 static const char fgClassID
;
77 StringEnumeration
*tzenum
;
80 const char TestZIDEnumeration::fgClassID
= 0;
82 TestZIDEnumeration::TestZIDEnumeration(UBool all
)
84 UErrorCode status
= U_ZERO_ERROR
;
86 tzenum
= TimeZone::createEnumeration();
87 len
= tzenum
->count(status
);
90 len
= UPRV_LENGTHOF(TESTZIDS
);
94 TestZIDEnumeration::~TestZIDEnumeration() {
101 TestZIDEnumeration::snext(UErrorCode
& status
) {
102 if (tzenum
!= NULL
) {
103 return tzenum
->snext(status
);
104 } else if (U_SUCCESS(status
) && idx
< len
) {
105 unistr
= UnicodeString(TESTZIDS
[idx
++], "");
112 TestZIDEnumeration::reset(UErrorCode
& status
) {
113 if (tzenum
!= NULL
) {
114 tzenum
->reset(status
);
121 void TimeZoneRuleTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/ )
124 logln("TestSuite TestTimeZoneRule");
127 CASE(0, TestSimpleRuleBasedTimeZone
);
128 CASE(1, TestHistoricalRuleBasedTimeZone
);
129 CASE(2, TestOlsonTransition
);
130 CASE(3, TestRBTZTransition
);
131 CASE(4, TestHasEquivalentTransitions
);
132 CASE(5, TestVTimeZoneRoundTrip
);
133 CASE(6, TestVTimeZoneRoundTripPartial
);
134 CASE(7, TestVTimeZoneSimpleWrite
);
135 CASE(8, TestVTimeZoneHeaderProps
);
136 CASE(9, TestGetSimpleRules
);
137 CASE(10, TestTimeZoneRuleCoverage
);
138 CASE(11, TestSimpleTimeZoneCoverage
);
139 CASE(12, TestVTimeZoneCoverage
);
140 CASE(13, TestVTimeZoneParse
);
143 CASE(16, TestVTimeZoneWrapper
);
145 default: name
= ""; break;
150 * Compare SimpleTimeZone with equivalent RBTZ
153 TimeZoneRuleTest::TestSimpleRuleBasedTimeZone(void) {
154 UErrorCode status
= U_ZERO_ERROR
;
155 SimpleTimeZone
stz(-1*HOUR
, "TestSTZ",
156 UCAL_SEPTEMBER
, -30, -UCAL_SATURDAY
, 1*HOUR
, SimpleTimeZone::WALL_TIME
,
157 UCAL_FEBRUARY
, 2, UCAL_SUNDAY
, 1*HOUR
, SimpleTimeZone::WALL_TIME
,
159 if (U_FAILURE(status
)) {
160 errln("FAIL: Couldn't create SimpleTimezone.");
164 AnnualTimeZoneRule
*atzr
;
165 int32_t STARTYEAR
= 2000;
167 InitialTimeZoneRule
*ir
= new InitialTimeZoneRule(
168 "RBTZ_Initial", // Initial time Name
169 -1*HOUR
, // Raw offset
170 1*HOUR
); // DST saving amount
173 RuleBasedTimeZone
*rbtz1
= new RuleBasedTimeZone("RBTZ1", ir
->clone());
174 dtr
= new DateTimeRule(UCAL_SEPTEMBER
, 30, UCAL_SATURDAY
, FALSE
,
175 1*HOUR
, DateTimeRule::WALL_TIME
); // SUN<=30 in September, at 1AM wall time
176 atzr
= new AnnualTimeZoneRule("RBTZ_DST1",
177 -1*HOUR
/*rawOffset*/, 1*HOUR
/*dstSavings*/, dtr
,
178 STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
179 rbtz1
->addTransitionRule(atzr
, status
);
180 if (U_FAILURE(status
)) {
181 errln("FAIL: couldn't add AnnualTimeZoneRule 1-1.");
183 dtr
= new DateTimeRule(UCAL_FEBRUARY
, 2, UCAL_SUNDAY
,
184 1*HOUR
, DateTimeRule::WALL_TIME
); // 2nd Sunday in February, at 1AM wall time
185 atzr
= new AnnualTimeZoneRule("RBTZ_STD1",
186 -1*HOUR
/*rawOffset*/, 0 /*dstSavings*/, dtr
,
187 STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
188 rbtz1
->addTransitionRule(atzr
, status
);
189 if (U_FAILURE(status
)) {
190 errln("FAIL: couldn't add AnnualTimeZoneRule 1-2.");
192 rbtz1
->complete(status
);
193 if (U_FAILURE(status
)) {
194 errln("FAIL: couldn't complete RBTZ 1.");
197 // Equivalent, but different date rule type
198 RuleBasedTimeZone
*rbtz2
= new RuleBasedTimeZone("RBTZ2", ir
->clone());
199 dtr
= new DateTimeRule(UCAL_SEPTEMBER
, -1, UCAL_SATURDAY
,
200 1*HOUR
, DateTimeRule::WALL_TIME
); // Last Sunday in September at 1AM wall time
201 atzr
= new AnnualTimeZoneRule("RBTZ_DST2", -1*HOUR
, 1*HOUR
, dtr
, STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
202 rbtz2
->addTransitionRule(atzr
, status
);
203 if (U_FAILURE(status
)) {
204 errln("FAIL: couldn't add AnnualTimeZoneRule 2-1.");
206 dtr
= new DateTimeRule(UCAL_FEBRUARY
, 8, UCAL_SUNDAY
, true,
207 1*HOUR
, DateTimeRule::WALL_TIME
); // SUN>=8 in February, at 1AM wall time
208 atzr
= new AnnualTimeZoneRule("RBTZ_STD2", -1*HOUR
, 0, dtr
, STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
209 rbtz2
->addTransitionRule(atzr
, status
);
210 if (U_FAILURE(status
)) {
211 errln("FAIL: couldn't add AnnualTimeZoneRule 2-2.");
213 rbtz2
->complete(status
);
214 if (U_FAILURE(status
)) {
215 errln("FAIL: couldn't complete RBTZ 2");
218 // Equivalent, but different time rule type
219 RuleBasedTimeZone
*rbtz3
= new RuleBasedTimeZone("RBTZ3", ir
->clone());
220 dtr
= new DateTimeRule(UCAL_SEPTEMBER
, 30, UCAL_SATURDAY
, false,
221 2*HOUR
, DateTimeRule::UTC_TIME
);
222 atzr
= new AnnualTimeZoneRule("RBTZ_DST3", -1*HOUR
, 1*HOUR
, dtr
, STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
223 rbtz3
->addTransitionRule(atzr
, status
);
224 if (U_FAILURE(status
)) {
225 errln("FAIL: couldn't add AnnualTimeZoneRule 3-1.");
227 dtr
= new DateTimeRule(UCAL_FEBRUARY
, 2, UCAL_SUNDAY
,
228 0*HOUR
, DateTimeRule::STANDARD_TIME
);
229 atzr
= new AnnualTimeZoneRule("RBTZ_STD3", -1*HOUR
, 0, dtr
, STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
230 rbtz3
->addTransitionRule(atzr
, status
);
231 if (U_FAILURE(status
)) {
232 errln("FAIL: couldn't add AnnualTimeZoneRule 3-2.");
234 rbtz3
->complete(status
);
235 if (U_FAILURE(status
)) {
236 errln("FAIL: couldn't complete RBTZ 3");
239 // Check equivalency for 10 years
240 UDate start
= getUTCMillis(STARTYEAR
, UCAL_JANUARY
, 1);
241 UDate until
= getUTCMillis(STARTYEAR
+ 10, UCAL_JANUARY
, 1);
243 if (!(stz
.hasEquivalentTransitions(*rbtz1
, start
, until
, TRUE
, status
))) {
244 errln("FAIL: rbtz1 must be equivalent to the SimpleTimeZone in the time range.");
246 if (U_FAILURE(status
)) {
247 errln("FAIL: error returned from hasEquivalentTransitions");
249 if (!(stz
.hasEquivalentTransitions(*rbtz2
, start
, until
, TRUE
, status
))) {
250 errln("FAIL: rbtz2 must be equivalent to the SimpleTimeZone in the time range.");
252 if (U_FAILURE(status
)) {
253 errln("FAIL: error returned from hasEquivalentTransitions");
255 if (!(stz
.hasEquivalentTransitions(*rbtz3
, start
, until
, TRUE
, status
))) {
256 errln("FAIL: rbtz3 must be equivalent to the SimpleTimeZone in the time range.");
258 if (U_FAILURE(status
)) {
259 errln("FAIL: error returned from hasEquivalentTransitions");
263 if (rbtz1
->hasSameRules(*rbtz2
)) {
264 errln("FAIL: rbtz1 and rbtz2 have different rules, but returned true.");
266 if (rbtz1
->hasSameRules(*rbtz3
)) {
267 errln("FAIL: rbtz1 and rbtz3 have different rules, but returned true.");
269 RuleBasedTimeZone
*rbtz1c
= (RuleBasedTimeZone
*)rbtz1
->clone();
270 if (!rbtz1
->hasSameRules(*rbtz1c
)) {
271 errln("FAIL: Cloned RuleBasedTimeZone must have the same rules with the original.");
275 int32_t era
, year
, month
, dayOfMonth
, dayOfWeek
, millisInDay
;
277 int32_t offset
, dstSavings
;
280 GregorianCalendar
*cal
= new GregorianCalendar(status
);
281 if (U_FAILURE(status
)) {
282 dataerrln("FAIL: Could not create a Gregorian calendar instance.: %s", u_errorName(status
));
289 cal
->setTimeZone(*rbtz1
);
293 cal
->set(UCAL_ERA
, GregorianCalendar::BC
);
294 cal
->set(1000, UCAL_JANUARY
, 1);
296 era
= cal
->get(UCAL_ERA
, status
);
297 year
= cal
->get(UCAL_YEAR
, status
);
298 month
= cal
->get(UCAL_MONTH
, status
);
299 dayOfMonth
= cal
->get(UCAL_DAY_OF_MONTH
, status
);
300 dayOfWeek
= cal
->get(UCAL_DAY_OF_WEEK
, status
);
301 millisInDay
= cal
->get(UCAL_MILLISECONDS_IN_DAY
, status
);
302 time
= cal
->getTime(status
);
303 if (U_FAILURE(status
)) {
304 errln("FAIL: Could not get calendar field values.");
306 offset
= rbtz1
->getOffset(era
, year
, month
, dayOfMonth
, dayOfWeek
, millisInDay
, status
);
307 if (U_FAILURE(status
)) {
308 errln("FAIL: getOffset(7 args) failed.");
311 errln(UnicodeString("FAIL: Invalid time zone offset: ") + offset
+ " /expected: 0");
313 dst
= rbtz1
->inDaylightTime(time
, status
);
314 if (U_FAILURE(status
)) {
315 errln("FAIL: inDaylightTime failed.");
318 errln("FAIL: Invalid daylight saving time");
320 rbtz1
->getOffset(time
, TRUE
, offset
, dstSavings
, status
);
321 if (U_FAILURE(status
)) {
322 errln("FAIL: getOffset(5 args) failed.");
324 if (offset
!= -3600000) {
325 errln(UnicodeString("FAIL: Invalid time zone raw offset: ") + offset
+ " /expected: -3600000");
327 if (dstSavings
!= 3600000) {
328 errln(UnicodeString("FAIL: Invalid DST amount: ") + dstSavings
+ " /expected: 3600000");
332 cal
->set(UCAL_ERA
, GregorianCalendar::AD
);
333 cal
->set(2000, UCAL_JULY
, 1);
335 era
= cal
->get(UCAL_ERA
, status
);
336 year
= cal
->get(UCAL_YEAR
, status
);
337 month
= cal
->get(UCAL_MONTH
, status
);
338 dayOfMonth
= cal
->get(UCAL_DAY_OF_MONTH
, status
);
339 dayOfWeek
= cal
->get(UCAL_DAY_OF_WEEK
, status
);
340 millisInDay
= cal
->get(UCAL_MILLISECONDS_IN_DAY
, status
);
341 time
= cal
->getTime(status
);
342 if (U_FAILURE(status
)) {
343 errln("FAIL: Could not get calendar field values.");
345 offset
= rbtz1
->getOffset(era
, year
, month
, dayOfMonth
, dayOfWeek
, millisInDay
, status
);
346 if (U_FAILURE(status
)) {
347 errln("FAIL: getOffset(7 args) failed.");
349 if (offset
!= -3600000) {
350 errln((UnicodeString
)"FAIL: Invalid time zone offset: " + offset
+ " /expected: -3600000");
352 dst
= rbtz1
->inDaylightTime(time
, status
);
353 if (U_FAILURE(status
)) {
354 errln("FAIL: inDaylightTime failed.");
357 errln("FAIL: Invalid daylight saving time");
359 rbtz1
->getOffset(time
, TRUE
, offset
, dstSavings
, status
);
360 if (U_FAILURE(status
)) {
361 errln("FAIL: getOffset(5 args) failed.");
363 if (offset
!= -3600000) {
364 errln((UnicodeString
)"FAIL: Invalid time zone raw offset: " + offset
+ " /expected: -3600000");
366 if (dstSavings
!= 0) {
367 errln((UnicodeString
)"FAIL: Invalid DST amount: " + dstSavings
+ " /expected: 0");
371 offset
= rbtz1
->getRawOffset();
372 if (offset
!= -1*HOUR
) {
373 errln((UnicodeString
)"FAIL: Invalid time zone raw offset returned by getRawOffset: "
374 + offset
+ " /expected: -3600000");
378 RuleBasedTimeZone
rbtz0("RBTZ1", ir
->clone());
379 if (rbtz0
== *rbtz1
|| !(rbtz0
!= *rbtz1
)) {
380 errln("FAIL: RuleBasedTimeZone rbtz0 is not equal to rbtz1, but got wrong result");
383 if (rbtz0
!= *rbtz1
|| !(rbtz0
== *rbtz1
)) {
384 errln("FAIL: RuleBasedTimeZone rbtz0 is equal to rbtz1, but got wrong result");
388 const int32_t RAW
= -10*HOUR
;
389 rbtz0
.setRawOffset(RAW
);
390 if (rbtz0
.getRawOffset() != RAW
) {
391 logln("setRawOffset is implemented in RuleBasedTimeZone");
395 if (!rbtz1
->useDaylightTime()) {
396 errln("FAIL: useDaylightTime returned FALSE");
399 // Try to add 3rd final rule
400 dtr
= new DateTimeRule(UCAL_OCTOBER
, 15, 1*HOUR
, DateTimeRule::WALL_TIME
);
401 atzr
= new AnnualTimeZoneRule("3RD_ATZ", -1*HOUR
, 2*HOUR
, dtr
, STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
402 rbtz1
->addTransitionRule(atzr
, status
);
403 if (U_SUCCESS(status
)) {
404 errln("FAIL: 3rd final rule must be rejected");
409 // Try to add an initial rule
410 InitialTimeZoneRule
*ir1
= new InitialTimeZoneRule("Test Initial", 2*HOUR
, 0);
411 rbtz1
->addTransitionRule(ir1
, status
);
412 if (U_SUCCESS(status
)) {
413 errln("FAIL: InitialTimeZoneRule must be rejected");
427 * Test equivalency between OlsonTimeZone and custom RBTZ representing the
428 * equivalent rules in a certain time range
431 TimeZoneRuleTest::TestHistoricalRuleBasedTimeZone(void) {
432 UErrorCode status
= U_ZERO_ERROR
;
434 // Compare to America/New_York with equivalent RBTZ
435 BasicTimeZone
*ny
= (BasicTimeZone
*)TimeZone::createTimeZone("America/New_York");
438 InitialTimeZoneRule
*ir
= new InitialTimeZoneRule("EST", -5*HOUR
, 0);
439 RuleBasedTimeZone
*rbtz
= new RuleBasedTimeZone("EST5EDT", ir
);
442 AnnualTimeZoneRule
*tzr
;
445 dtr
= new DateTimeRule(UCAL_OCTOBER
, -1, UCAL_SUNDAY
,
446 2*HOUR
, DateTimeRule::WALL_TIME
); // Last Sunday in October, at 2AM wall time
447 tzr
= new AnnualTimeZoneRule("EST", -5*HOUR
/*rawOffset*/, 0 /*dstSavings*/, dtr
, 1967, 2006);
448 rbtz
->addTransitionRule(tzr
, status
);
449 if (U_FAILURE(status
)) {
450 errln("FAIL: couldn't add AnnualTimeZoneRule 1.");
453 dtr
= new DateTimeRule(UCAL_NOVEMBER
, 1, UCAL_SUNDAY
,
454 true, 2*HOUR
, DateTimeRule::WALL_TIME
); // SUN>=1 in November, at 2AM wall time
455 tzr
= new AnnualTimeZoneRule("EST", -5*HOUR
, 0, dtr
, 2007, AnnualTimeZoneRule::MAX_YEAR
);
456 rbtz
->addTransitionRule(tzr
, status
);
457 if (U_FAILURE(status
)) {
458 errln("FAIL: couldn't add AnnualTimeZoneRule 2.");
461 // Daylight saving time
462 dtr
= new DateTimeRule(UCAL_APRIL
, -1, UCAL_SUNDAY
,
463 2*HOUR
, DateTimeRule::WALL_TIME
); // Last Sunday in April, at 2AM wall time
464 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 1967, 1973);
465 rbtz
->addTransitionRule(tzr
, status
);
466 if (U_FAILURE(status
)) {
467 errln("FAIL: couldn't add AnnualTimeZoneRule 3.");
470 dtr
= new DateTimeRule(UCAL_JANUARY
, 6,
471 2*HOUR
, DateTimeRule::WALL_TIME
); // January 6, at 2AM wall time
472 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 1974, 1974);
473 rbtz
->addTransitionRule(tzr
, status
);
474 if (U_FAILURE(status
)) {
475 errln("FAIL: couldn't add AnnualTimeZoneRule 4.");
478 dtr
= new DateTimeRule(UCAL_FEBRUARY
, 23,
479 2*HOUR
, DateTimeRule::WALL_TIME
); // February 23, at 2AM wall time
480 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 1975, 1975);
481 rbtz
->addTransitionRule(tzr
, status
);
482 if (U_FAILURE(status
)) {
483 errln("FAIL: couldn't add AnnualTimeZoneRule 5.");
486 dtr
= new DateTimeRule(UCAL_APRIL
, -1, UCAL_SUNDAY
,
487 2*HOUR
, DateTimeRule::WALL_TIME
); // Last Sunday in April, at 2AM wall time
488 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 1976, 1986);
489 rbtz
->addTransitionRule(tzr
, status
);
490 if (U_FAILURE(status
)) {
491 errln("FAIL: couldn't add AnnualTimeZoneRule 6.");
494 dtr
= new DateTimeRule(UCAL_APRIL
, 1, UCAL_SUNDAY
,
495 true, 2*HOUR
, DateTimeRule::WALL_TIME
); // SUN>=1 in April, at 2AM wall time
496 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 1987, 2006);
497 rbtz
->addTransitionRule(tzr
, status
);
498 if (U_FAILURE(status
)) {
499 errln("FAIL: couldn't add AnnualTimeZoneRule 7.");
502 dtr
= new DateTimeRule(UCAL_MARCH
, 8, UCAL_SUNDAY
,
503 true, 2*HOUR
, DateTimeRule::WALL_TIME
); // SUN>=8 in March, at 2AM wall time
504 tzr
= new AnnualTimeZoneRule("EDT", -5*HOUR
, 1*HOUR
, dtr
, 2007, AnnualTimeZoneRule::MAX_YEAR
);
505 rbtz
->addTransitionRule(tzr
, status
);
506 if (U_FAILURE(status
)) {
507 errln("FAIL: couldn't add AnnualTimeZoneRule 7.");
510 rbtz
->complete(status
);
511 if (U_FAILURE(status
)) {
512 errln("FAIL: couldn't complete RBTZ.");
515 // hasEquivalentTransitions
516 UDate jan1_1950
= getUTCMillis(1950, UCAL_JANUARY
, 1);
517 UDate jan1_1967
= getUTCMillis(1971, UCAL_JANUARY
, 1);
518 UDate jan1_2010
= getUTCMillis(2010, UCAL_JANUARY
, 1);
520 if (!ny
->hasEquivalentTransitions(*rbtz
, jan1_1967
, jan1_2010
, TRUE
, status
)) {
521 dataerrln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010");
523 if (U_FAILURE(status
)) {
524 errln("FAIL: error returned from hasEquivalentTransitions for ny/rbtz 1967-2010");
526 if (ny
->hasEquivalentTransitions(*rbtz
, jan1_1950
, jan1_2010
, TRUE
, status
)) {
527 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010");
529 if (U_FAILURE(status
)) {
530 errln("FAIL: error returned from hasEquivalentTransitions for ny/rbtz 1950-2010");
533 // Same with above, but calling RBTZ#hasEquivalentTransitions against OlsonTimeZone
534 if (!rbtz
->hasEquivalentTransitions(*ny
, jan1_1967
, jan1_2010
, TRUE
, status
)) {
535 dataerrln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010 ");
537 if (U_FAILURE(status
)) {
538 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/ny 1967-2010");
540 if (rbtz
->hasEquivalentTransitions(*ny
, jan1_1950
, jan1_2010
, TRUE
, status
)) {
541 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010");
543 if (U_FAILURE(status
)) {
544 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/ny 1950-2010");
548 if (ny
->hasSameRules(*rbtz
) || rbtz
->hasSameRules(*ny
)) {
549 errln("FAIL: hasSameRules must return false");
551 RuleBasedTimeZone
*rbtzc
= (RuleBasedTimeZone
*)rbtz
->clone();
552 if (!rbtz
->hasSameRules(*rbtzc
) || !rbtz
->hasEquivalentTransitions(*rbtzc
, jan1_1950
, jan1_2010
, TRUE
, status
)) {
553 errln("FAIL: hasSameRules/hasEquivalentTransitions must return true for cloned RBTZs");
555 if (U_FAILURE(status
)) {
556 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/rbtzc 1950-2010");
560 getUTCMillis(2006, UCAL_MARCH
, 15),
561 getUTCMillis(2006, UCAL_NOVEMBER
, 1),
562 getUTCMillis(2007, UCAL_MARCH
, 15),
563 getUTCMillis(2007, UCAL_NOVEMBER
, 1),
564 getUTCMillis(2008, UCAL_MARCH
, 15),
565 getUTCMillis(2008, UCAL_NOVEMBER
, 1),
568 int32_t offset1
, dst1
;
569 int32_t offset2
, dst2
;
571 for (int i
= 0; times
[i
] != 0; i
++) {
572 // Check getOffset - must return the same results for these time data
573 rbtz
->getOffset(times
[i
], FALSE
, offset1
, dst1
, status
);
574 if (U_FAILURE(status
)) {
575 errln("FAIL: rbtz->getOffset failed");
577 ny
->getOffset(times
[i
], FALSE
, offset2
, dst2
, status
);
578 if (U_FAILURE(status
)) {
579 errln("FAIL: ny->getOffset failed");
581 if (offset1
!= offset2
|| dst1
!= dst2
) {
582 dataerrln("FAIL: Incompatible time zone offset/dstSavings for ny and rbtz");
585 // Check inDaylightTime
586 if (rbtz
->inDaylightTime(times
[i
], status
) != ny
->inDaylightTime(times
[i
], status
)) {
587 dataerrln("FAIL: Incompatible daylight saving time for ny and rbtz");
589 if (U_FAILURE(status
)) {
590 errln("FAIL: inDaylightTime failed");
600 * Check if transitions returned by getNextTransition/getPreviousTransition
601 * are actual time transitions.
604 TimeZoneRuleTest::TestOlsonTransition(void) {
606 const int32_t TESTYEARS
[][2] = {
607 {1895, 1905}, // including int32 minimum second
608 {1965, 1975}, // including the epoch
609 {1995, 2015}, // practical year range
613 UErrorCode status
= U_ZERO_ERROR
;
614 TestZIDEnumeration
tzenum(!quick
);
616 const UnicodeString
*tzid
= tzenum
.snext(status
);
620 if (U_FAILURE(status
)) {
621 errln("FAIL: error returned while enumerating timezone IDs.");
624 BasicTimeZone
*tz
= (BasicTimeZone
*)TimeZone::createTimeZone(*tzid
);
625 for (int32_t i
= 0; TESTYEARS
[i
][0] != 0 || TESTYEARS
[i
][1] != 0; i
++) {
626 UDate lo
= getUTCMillis(TESTYEARS
[i
][0], UCAL_JANUARY
, 1);
627 UDate hi
= getUTCMillis(TESTYEARS
[i
][1], UCAL_JANUARY
, 1);
628 verifyTransitions(*tz
, lo
, hi
);
635 * Check if an OlsonTimeZone and its equivalent RBTZ have the exact same
639 TimeZoneRuleTest::TestRBTZTransition(void) {
640 const int32_t STARTYEARS
[] = {
648 UErrorCode status
= U_ZERO_ERROR
;
649 TestZIDEnumeration
tzenum(!quick
);
651 const UnicodeString
*tzid
= tzenum
.snext(status
);
655 if (U_FAILURE(status
)) {
656 errln("FAIL: error returned while enumerating timezone IDs.");
659 BasicTimeZone
*tz
= (BasicTimeZone
*)TimeZone::createTimeZone(*tzid
);
660 int32_t ruleCount
= tz
->countTransitionRules(status
);
662 const InitialTimeZoneRule
*initial
;
663 const TimeZoneRule
**trsrules
= new const TimeZoneRule
*[ruleCount
];
664 tz
->getTimeZoneRules(initial
, trsrules
, ruleCount
, status
);
665 if (U_FAILURE(status
)) {
666 errln((UnicodeString
)"FAIL: failed to get the TimeZoneRules from time zone " + *tzid
);
668 RuleBasedTimeZone
*rbtz
= new RuleBasedTimeZone(*tzid
, initial
->clone());
669 if (U_FAILURE(status
)) {
670 errln((UnicodeString
)"FAIL: failed to get the transition rule count from time zone " + *tzid
);
672 for (int32_t i
= 0; i
< ruleCount
; i
++) {
673 rbtz
->addTransitionRule(trsrules
[i
]->clone(), status
);
674 if (U_FAILURE(status
)) {
675 errln((UnicodeString
)"FAIL: failed to add a transition rule at index " + i
+ " to the RBTZ for " + *tzid
);
678 rbtz
->complete(status
);
679 if (U_FAILURE(status
)) {
680 errln((UnicodeString
)"FAIL: complete() failed for the RBTZ for " + *tzid
);
683 for (int32_t idx
= 0; STARTYEARS
[idx
] != 0; idx
++) {
684 UDate start
= getUTCMillis(STARTYEARS
[idx
], UCAL_JANUARY
, 1);
685 UDate until
= getUTCMillis(STARTYEARS
[idx
] + 20, UCAL_JANUARY
, 1);
686 // Compare the original OlsonTimeZone with the RBTZ starting the startTime for 20 years
689 compareTransitionsAscending(*tz
, *rbtz
, start
, until
, FALSE
);
690 // Ascending/inclusive
691 compareTransitionsAscending(*tz
, *rbtz
, start
+ 1, until
, TRUE
);
693 compareTransitionsDescending(*tz
, *rbtz
, start
, until
, FALSE
);
694 // Descending/inclusive
695 compareTransitionsDescending(*tz
, *rbtz
, start
+ 1, until
, TRUE
);
704 TimeZoneRuleTest::TestHasEquivalentTransitions(void) {
705 // America/New_York and America/Indiana/Indianapolis are equivalent
707 UErrorCode status
= U_ZERO_ERROR
;
708 BasicTimeZone
*newyork
= (BasicTimeZone
*)TimeZone::createTimeZone("America/New_York");
709 BasicTimeZone
*indianapolis
= (BasicTimeZone
*)TimeZone::createTimeZone("America/Indiana/Indianapolis");
710 BasicTimeZone
*gmt_5
= (BasicTimeZone
*)TimeZone::createTimeZone("Etc/GMT+5");
712 UDate jan1_1971
= getUTCMillis(1971, UCAL_JANUARY
, 1);
713 UDate jan1_2005
= getUTCMillis(2005, UCAL_JANUARY
, 1);
714 UDate jan1_2006
= getUTCMillis(2006, UCAL_JANUARY
, 1);
715 UDate jan1_2007
= getUTCMillis(2007, UCAL_JANUARY
, 1);
716 UDate jan1_2011
= getUTCMillis(2010, UCAL_JANUARY
, 1);
718 if (newyork
->hasEquivalentTransitions(*indianapolis
, jan1_2005
, jan1_2011
, TRUE
, status
)) {
719 dataerrln("FAIL: New_York is not equivalent to Indianapolis between 2005 and 2010");
721 if (U_FAILURE(status
)) {
722 errln("FAIL: error status is returned from hasEquivalentTransition");
724 if (!newyork
->hasEquivalentTransitions(*indianapolis
, jan1_2006
, jan1_2011
, TRUE
, status
)) {
725 errln("FAIL: New_York is equivalent to Indianapolis between 2006 and 2010");
727 if (U_FAILURE(status
)) {
728 errln("FAIL: error status is returned from hasEquivalentTransition");
731 if (!indianapolis
->hasEquivalentTransitions(*gmt_5
, jan1_1971
, jan1_2006
, TRUE
, status
)) {
732 errln("FAIL: Indianapolis is equivalent to GMT+5 between 1971 and 2005");
734 if (U_FAILURE(status
)) {
735 errln("FAIL: error status is returned from hasEquivalentTransition");
737 if (indianapolis
->hasEquivalentTransitions(*gmt_5
, jan1_1971
, jan1_2007
, TRUE
, status
)) {
738 dataerrln("FAIL: Indianapolis is not equivalent to GMT+5 between 1971 and 2006");
740 if (U_FAILURE(status
)) {
741 errln("FAIL: error status is returned from hasEquivalentTransition");
745 BasicTimeZone
*newyork2
= (BasicTimeZone
*)newyork
->clone();
746 if (!newyork
->hasEquivalentTransitions(*newyork2
, jan1_1971
, jan1_2011
, FALSE
, status
)) {
747 errln("FAIL: Cloned TimeZone must have the same transitions");
749 if (U_FAILURE(status
)) {
750 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/newyork2");
752 if (!newyork
->hasEquivalentTransitions(*newyork2
, jan1_1971
, jan1_2011
, TRUE
, status
)) {
753 errln("FAIL: Cloned TimeZone must have the same transitions");
755 if (U_FAILURE(status
)) {
756 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/newyork2");
759 // America/New_York and America/Los_Angeles has same DST start rules, but
760 // raw offsets are different
761 BasicTimeZone
*losangeles
= (BasicTimeZone
*)TimeZone::createTimeZone("America/Los_Angeles");
762 if (newyork
->hasEquivalentTransitions(*losangeles
, jan1_2006
, jan1_2011
, TRUE
, status
)) {
763 dataerrln("FAIL: New_York is not equivalent to Los Angeles, but returned true");
765 if (U_FAILURE(status
)) {
766 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/losangeles");
777 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format, create a new
778 * VTimeZone from the VTIMEZONE data, then compare transitions
781 TimeZoneRuleTest::TestVTimeZoneRoundTrip(void) {
782 UDate startTime
= getUTCMillis(1850, UCAL_JANUARY
, 1);
783 UDate endTime
= getUTCMillis(2050, UCAL_JANUARY
, 1);
785 UErrorCode status
= U_ZERO_ERROR
;
786 TestZIDEnumeration
tzenum(!quick
);
788 const UnicodeString
*tzid
= tzenum
.snext(status
);
792 if (U_FAILURE(status
)) {
793 errln("FAIL: error returned while enumerating timezone IDs.");
796 BasicTimeZone
*tz
= (BasicTimeZone
*)TimeZone::createTimeZone(*tzid
);
797 VTimeZone
*vtz_org
= VTimeZone::createVTimeZoneByID(*tzid
);
798 vtz_org
->setTZURL("http://source.icu-project.org/timezone");
799 vtz_org
->setLastModified(Calendar::getNow());
800 VTimeZone
*vtz_new
= NULL
;
801 UnicodeString vtzdata
;
802 // Write out VTIMEZONE data
803 vtz_org
->write(vtzdata
, status
);
804 if (U_FAILURE(status
)) {
805 errln((UnicodeString
)"FAIL: error returned while writing time zone rules for " +
806 *tzid
+ " into VTIMEZONE format.");
808 // Read VTIMEZONE data
809 vtz_new
= VTimeZone::createVTimeZone(vtzdata
, status
);
810 if (U_FAILURE(status
)) {
811 errln((UnicodeString
)"FAIL: error returned while reading VTIMEZONE data for " + *tzid
);
813 // Write out VTIMEZONE one more time
814 UnicodeString vtzdata1
;
815 vtz_new
->write(vtzdata1
, status
);
816 if (U_FAILURE(status
)) {
817 errln((UnicodeString
)"FAIL: error returned while writing time zone rules for " +
818 *tzid
+ "(vtz_new) into VTIMEZONE format.");
820 // Make sure VTIMEZONE data is exactly same with the first one
821 if (vtzdata
!= vtzdata1
) {
822 errln((UnicodeString
)"FAIL: different VTIMEZONE data after round trip for " + *tzid
);
825 // Check equivalency after the first transition.
826 // The DST information before the first transition might be lost
827 // because there is no good way to represent the initial time with
829 int32_t raw1
, raw2
, dst1
, dst2
;
830 tz
->getOffset(startTime
, FALSE
, raw1
, dst1
, status
);
831 vtz_new
->getOffset(startTime
, FALSE
, raw2
, dst2
, status
);
832 if (U_FAILURE(status
)) {
833 errln("FAIL: error status is returned from getOffset");
835 if (raw1
+ dst1
!= raw2
+ dst2
) {
836 errln("FAIL: VTimeZone for " + *tzid
+
837 " is not equivalent to its OlsonTimeZone corresponding at "
838 + dateToString(startTime
));
840 TimeZoneTransition trans
;
841 UBool avail
= tz
->getNextTransition(startTime
, FALSE
, trans
);
843 if (!vtz_new
->hasEquivalentTransitions(*tz
, trans
.getTime(),
844 endTime
, TRUE
, status
)) {
845 int32_t maxDelta
= 1000;
846 if (!hasEquivalentTransitions(*vtz_new
, *tz
, trans
.getTime() + maxDelta
,
847 endTime
, TRUE
, maxDelta
, status
)) {
848 errln("FAIL: VTimeZone for " + *tzid
+
849 " is not equivalent to its OlsonTimeZone corresponding.");
851 logln("VTimeZone for " + *tzid
+
852 " differs from its OlsonTimeZone corresponding with maximum transition time delta - " + maxDelta
);
855 if (U_FAILURE(status
)) {
856 errln("FAIL: error status is returned from hasEquivalentTransition");
861 if (vtz_new
!= NULL
) {
872 * Write out time zone rules of OlsonTimeZone after a cutover date into VTIMEZONE format,
873 * create a new VTimeZone from the VTIMEZONE data, then compare transitions
876 TimeZoneRuleTest::TestVTimeZoneRoundTripPartial(void) {
877 const int32_t STARTYEARS
[] = {
883 UDate endTime
= getUTCMillis(2050, UCAL_JANUARY
, 1);
885 UErrorCode status
= U_ZERO_ERROR
;
886 TestZIDEnumeration
tzenum(!quick
);
888 const UnicodeString
*tzid
= tzenum
.snext(status
);
892 if (U_FAILURE(status
)) {
893 errln("FAIL: error returned while enumerating timezone IDs.");
896 BasicTimeZone
*tz
= (BasicTimeZone
*)TimeZone::createTimeZone(*tzid
);
897 VTimeZone
*vtz_org
= VTimeZone::createVTimeZoneByID(*tzid
);
898 VTimeZone
*vtz_new
= NULL
;
899 UnicodeString vtzdata
;
901 for (int32_t i
= 0; STARTYEARS
[i
] != 0; i
++) {
902 // Write out VTIMEZONE
903 UDate startTime
= getUTCMillis(STARTYEARS
[i
], UCAL_JANUARY
, 1);
904 vtz_org
->write(startTime
, vtzdata
, status
);
905 if (U_FAILURE(status
)) {
906 errln((UnicodeString
)"FAIL: error returned while writing time zone rules for " +
907 *tzid
+ " into VTIMEZONE format since " + dateToString(startTime
));
909 // Read VTIMEZONE data
910 vtz_new
= VTimeZone::createVTimeZone(vtzdata
, status
);
911 if (U_FAILURE(status
)) {
912 errln((UnicodeString
)"FAIL: error returned while reading VTIMEZONE data for " + *tzid
913 + " since " + dateToString(startTime
));
915 // Check equivalency after the first transition.
916 // The DST information before the first transition might be lost
917 // because there is no good way to represent the initial time with
919 int32_t raw1
, raw2
, dst1
, dst2
;
920 tz
->getOffset(startTime
, FALSE
, raw1
, dst1
, status
);
921 vtz_new
->getOffset(startTime
, FALSE
, raw2
, dst2
, status
);
922 if (U_FAILURE(status
)) {
923 errln("FAIL: error status is returned from getOffset");
925 if (raw1
+ dst1
!= raw2
+ dst2
) {
926 errln("FAIL: VTimeZone for " + *tzid
+
927 " is not equivalent to its OlsonTimeZone corresponding at "
928 + dateToString(startTime
));
930 TimeZoneTransition trans
;
931 UBool avail
= tz
->getNextTransition(startTime
, FALSE
, trans
);
933 if (!vtz_new
->hasEquivalentTransitions(*tz
, trans
.getTime(),
934 endTime
, TRUE
, status
)) {
935 int32_t maxDelta
= 1000;
936 if (!hasEquivalentTransitions(*vtz_new
, *tz
, trans
.getTime() + maxDelta
,
937 endTime
, TRUE
, maxDelta
, status
)) {
938 errln("FAIL: VTimeZone for " + *tzid
+
939 " is not equivalent to its OlsonTimeZone corresponding.");
941 logln("VTimeZone for " + *tzid
+
942 " differs from its OlsonTimeZone corresponding with maximum transition time delta - " + maxDelta
);
946 if (U_FAILURE(status
)) {
947 errln("FAIL: error status is returned from hasEquivalentTransition");
953 if (vtz_new
!= NULL
) {
964 * Write out simple time zone rules from an OlsonTimeZone at various time into VTIMEZONE
965 * format and create a new VTimeZone from the VTIMEZONE data, then make sure the raw offset
966 * and DST savings are same in these two time zones.
969 TimeZoneRuleTest::TestVTimeZoneSimpleWrite(void) {
970 const int32_t TESTDATES
[][3] = {
971 {2006, UCAL_JANUARY
, 1},
972 {2006, UCAL_MARCH
, 15},
973 {2006, UCAL_MARCH
, 31},
974 {2006, UCAL_OCTOBER
, 25},
975 {2006, UCAL_NOVEMBER
, 1},
976 {2006, UCAL_NOVEMBER
, 5},
977 {2007, UCAL_JANUARY
, 1},
981 UErrorCode status
= U_ZERO_ERROR
;
982 TestZIDEnumeration
tzenum(!quick
);
984 const UnicodeString
*tzid
= tzenum
.snext(status
);
988 if (U_FAILURE(status
)) {
989 errln("FAIL: error returned while enumerating timezone IDs.");
992 VTimeZone
*vtz_org
= VTimeZone::createVTimeZoneByID(*tzid
);
993 VTimeZone
*vtz_new
= NULL
;
994 UnicodeString vtzdata
;
996 for (int32_t i
= 0; TESTDATES
[i
][0] != 0; i
++) {
997 // Write out VTIMEZONE
998 UDate time
= getUTCMillis(TESTDATES
[i
][0], TESTDATES
[i
][1], TESTDATES
[i
][2]);
999 vtz_org
->writeSimple(time
, vtzdata
, status
);
1000 if (U_FAILURE(status
)) {
1001 errln((UnicodeString
)"FAIL: error returned while writing simple time zone rules for " +
1002 *tzid
+ " into VTIMEZONE format at " + dateToString(time
));
1004 // Read VTIMEZONE data
1005 vtz_new
= VTimeZone::createVTimeZone(vtzdata
, status
);
1006 if (U_FAILURE(status
)) {
1007 errln((UnicodeString
)"FAIL: error returned while reading simple VTIMEZONE data for " + *tzid
1008 + " at " + dateToString(time
));
1010 // Check equivalency
1013 vtz_org
->getOffset(time
, FALSE
, raw0
, dst0
, status
);
1014 vtz_new
->getOffset(time
, FALSE
, raw1
, dst1
, status
);
1015 if (U_SUCCESS(status
)) {
1016 if (raw0
!= raw1
|| dst0
!= dst1
) {
1017 errln("FAIL: VTimeZone writeSimple for " + *tzid
+ " at "
1018 + dateToString(time
) + " failed to the round trip.");
1021 errln("FAIL: getOffset returns error status");
1025 if (vtz_new
!= NULL
) {
1035 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format with RFC2445 header TZURL and
1036 * LAST-MODIFIED, create a new VTimeZone from the VTIMEZONE data to see if the headers are preserved.
1039 TimeZoneRuleTest::TestVTimeZoneHeaderProps(void) {
1040 const UnicodeString
TESTURL1("http://source.icu-project.org");
1041 const UnicodeString
TESTURL2("http://www.ibm.com");
1043 UErrorCode status
= U_ZERO_ERROR
;
1044 UnicodeString tzurl
;
1046 UDate lastmod
= getUTCMillis(2007, UCAL_JUNE
, 1);
1047 VTimeZone
*vtz
= VTimeZone::createVTimeZoneByID("America/Chicago");
1048 vtz
->setTZURL(TESTURL1
);
1049 vtz
->setLastModified(lastmod
);
1051 // Roundtrip conversion
1052 UnicodeString vtzdata
;
1053 vtz
->write(vtzdata
, status
);
1054 VTimeZone
*newvtz1
= NULL
;
1055 if (U_FAILURE(status
)) {
1056 errln("FAIL: error returned while writing VTIMEZONE data 1");
1060 newvtz1
= VTimeZone::createVTimeZone(vtzdata
, status
);
1061 if (U_FAILURE(status
)) {
1062 errln("FAIL: error returned while loading VTIMEZONE data 1");
1064 // Check if TZURL and LAST-MODIFIED properties are preserved
1065 newvtz1
->getTZURL(tzurl
);
1066 if (tzurl
!= TESTURL1
) {
1067 errln("FAIL: TZURL 1 was not preserved");
1069 vtz
->getLastModified(lmod
);
1070 if (lastmod
!= lmod
) {
1071 errln("FAIL: LAST-MODIFIED was not preserved");
1075 if (U_SUCCESS(status
)) {
1076 // Set different tzurl
1077 newvtz1
->setTZURL(TESTURL2
);
1079 // Second roundtrip, with a cutover
1080 newvtz1
->write(vtzdata
, status
);
1081 if (U_FAILURE(status
)) {
1082 errln("FAIL: error returned while writing VTIMEZONE data 2");
1084 VTimeZone
*newvtz2
= VTimeZone::createVTimeZone(vtzdata
, status
);
1085 if (U_FAILURE(status
)) {
1086 errln("FAIL: error returned while loading VTIMEZONE data 2");
1088 // Check if TZURL and LAST-MODIFIED properties are preserved
1089 newvtz2
->getTZURL(tzurl
);
1090 if (tzurl
!= TESTURL2
) {
1091 errln("FAIL: TZURL was not preserved in the second roundtrip");
1093 vtz
->getLastModified(lmod
);
1094 if (lastmod
!= lmod
) {
1095 errln("FAIL: LAST-MODIFIED was not preserved in the second roundtrip");
1106 * Extract simple rules from an OlsonTimeZone and make sure the rule format matches
1107 * the expected format.
1110 TimeZoneRuleTest::TestGetSimpleRules(void) {
1111 UDate testTimes
[] = {
1112 getUTCMillis(1970, UCAL_JANUARY
, 1),
1113 getUTCMillis(2000, UCAL_MARCH
, 31),
1114 getUTCMillis(2005, UCAL_JULY
, 1),
1115 getUTCMillis(2010, UCAL_NOVEMBER
, 1),
1117 int32_t numTimes
= UPRV_LENGTHOF(testTimes
);
1118 UErrorCode status
= U_ZERO_ERROR
;
1119 TestZIDEnumeration
tzenum(!quick
);
1120 InitialTimeZoneRule
*initial
;
1121 AnnualTimeZoneRule
*std
, *dst
;
1122 for (int32_t i
= 0; i
< numTimes
; i
++) {
1124 const UnicodeString
*tzid
= tzenum
.snext(status
);
1128 if (U_FAILURE(status
)) {
1129 errln("FAIL: error returned while enumerating timezone IDs.");
1132 BasicTimeZone
*tz
= (BasicTimeZone
*)TimeZone::createTimeZone(*tzid
);
1135 tz
->getSimpleRulesNear(testTimes
[i
], initial
, std
, dst
, status
);
1136 if (U_FAILURE(status
)) {
1137 errln("FAIL: getSimpleRules failed.");
1140 if (initial
== NULL
) {
1141 errln("FAIL: initial rule must not be NULL");
1143 } else if (!((std
== NULL
&& dst
== NULL
) || (std
!= NULL
&& dst
!= NULL
))) {
1144 errln("FAIL: invalid std/dst pair.");
1148 const DateTimeRule
*dtr
= std
->getRule();
1149 if (dtr
->getDateRuleType() != DateTimeRule::DOW
) {
1150 errln("FAIL: simple std rull must use DateTimeRule::DOW as date rule.");
1153 if (dtr
->getTimeRuleType() != DateTimeRule::WALL_TIME
) {
1154 errln("FAIL: simple std rull must use DateTimeRule::WALL_TIME as time rule.");
1157 dtr
= dst
->getRule();
1158 if (dtr
->getDateRuleType() != DateTimeRule::DOW
) {
1159 errln("FAIL: simple dst rull must use DateTimeRule::DOW as date rule.");
1162 if (dtr
->getTimeRuleType() != DateTimeRule::WALL_TIME
) {
1163 errln("FAIL: simple dst rull must use DateTimeRule::WALL_TIME as time rule.");
1167 // Create an RBTZ from the rules and compare the offsets at the date
1168 RuleBasedTimeZone
*rbtz
= new RuleBasedTimeZone(*tzid
, initial
);
1170 rbtz
->addTransitionRule(std
, status
);
1171 if (U_FAILURE(status
)) {
1172 errln("FAIL: couldn't add std rule.");
1174 rbtz
->addTransitionRule(dst
, status
);
1175 if (U_FAILURE(status
)) {
1176 errln("FAIL: couldn't add dst rule.");
1179 rbtz
->complete(status
);
1180 if (U_FAILURE(status
)) {
1181 errln("FAIL: couldn't complete rbtz for " + *tzid
);
1184 int32_t raw0
, dst0
, raw1
, dst1
;
1185 tz
->getOffset(testTimes
[i
], FALSE
, raw0
, dst0
, status
);
1186 if (U_FAILURE(status
)) {
1187 errln("FAIL: couldn't get offsets from tz for " + *tzid
);
1189 rbtz
->getOffset(testTimes
[i
], FALSE
, raw1
, dst1
, status
);
1190 if (U_FAILURE(status
)) {
1191 errln("FAIL: couldn't get offsets from rbtz for " + *tzid
);
1193 if (raw0
!= raw1
|| dst0
!= dst1
) {
1194 errln("FAIL: rbtz created by simple rule does not match the original tz for tzid " + *tzid
);
1203 * API coverage tests for TimeZoneRule
1206 TimeZoneRuleTest::TestTimeZoneRuleCoverage(void) {
1207 UDate time1
= getUTCMillis(2005, UCAL_JULY
, 4);
1208 UDate time2
= getUTCMillis(2015, UCAL_JULY
, 4);
1209 UDate time3
= getUTCMillis(1950, UCAL_JULY
, 4);
1211 DateTimeRule
*dtr1
= new DateTimeRule(UCAL_FEBRUARY
, 29, UCAL_SUNDAY
, FALSE
,
1212 3*HOUR
, DateTimeRule::WALL_TIME
); // Last Sunday on or before Feb 29, at 3 AM, wall time
1213 DateTimeRule
*dtr2
= new DateTimeRule(UCAL_MARCH
, 11, 2*HOUR
,
1214 DateTimeRule::STANDARD_TIME
); // Mar 11, at 2 AM, standard time
1215 DateTimeRule
*dtr3
= new DateTimeRule(UCAL_OCTOBER
, -1, UCAL_SATURDAY
,
1216 6*HOUR
, DateTimeRule::UTC_TIME
); //Last Saturday in Oct, at 6 AM, UTC
1217 DateTimeRule
*dtr4
= new DateTimeRule(UCAL_MARCH
, 8, UCAL_SUNDAY
, TRUE
,
1218 2*HOUR
, DateTimeRule::WALL_TIME
); // First Sunday on or after Mar 8, at 2 AM, wall time
1220 AnnualTimeZoneRule
*a1
= new AnnualTimeZoneRule("a1", -3*HOUR
, 1*HOUR
, *dtr1
,
1221 2000, AnnualTimeZoneRule::MAX_YEAR
);
1222 AnnualTimeZoneRule
*a2
= new AnnualTimeZoneRule("a2", -3*HOUR
, 1*HOUR
, *dtr1
,
1223 2000, AnnualTimeZoneRule::MAX_YEAR
);
1224 AnnualTimeZoneRule
*a3
= new AnnualTimeZoneRule("a3", -3*HOUR
, 1*HOUR
, *dtr1
,
1227 InitialTimeZoneRule
*i1
= new InitialTimeZoneRule("i1", -3*HOUR
, 0);
1228 InitialTimeZoneRule
*i2
= new InitialTimeZoneRule("i2", -3*HOUR
, 0);
1229 InitialTimeZoneRule
*i3
= new InitialTimeZoneRule("i3", -3*HOUR
, 1*HOUR
);
1231 UDate trtimes1
[] = {0.0};
1232 UDate trtimes2
[] = {0.0, 10000000.0};
1234 TimeArrayTimeZoneRule
*t1
= new TimeArrayTimeZoneRule("t1", -3*HOUR
, 0, trtimes1
, 1, DateTimeRule::UTC_TIME
);
1235 TimeArrayTimeZoneRule
*t2
= new TimeArrayTimeZoneRule("t2", -3*HOUR
, 0, trtimes1
, 1, DateTimeRule::UTC_TIME
);
1236 TimeArrayTimeZoneRule
*t3
= new TimeArrayTimeZoneRule("t3", -3*HOUR
, 0, trtimes2
, 2, DateTimeRule::UTC_TIME
);
1237 TimeArrayTimeZoneRule
*t4
= new TimeArrayTimeZoneRule("t4", -3*HOUR
, 0, trtimes1
, 1, DateTimeRule::STANDARD_TIME
);
1238 TimeArrayTimeZoneRule
*t5
= new TimeArrayTimeZoneRule("t5", -4*HOUR
, 1*HOUR
, trtimes1
, 1, DateTimeRule::WALL_TIME
);
1240 // DateTimeRule::operator=/clone
1241 DateTimeRule
dtr0(UCAL_MAY
, 31, 2*HOUR
, DateTimeRule::WALL_TIME
);
1242 if (dtr0
== *dtr1
|| !(dtr0
!= *dtr1
)) {
1243 errln("FAIL: DateTimeRule dtr0 is not equal to dtr1, but got wrong result");
1246 if (dtr0
!= *dtr1
|| !(dtr0
== *dtr1
)) {
1247 errln("FAIL: DateTimeRule dtr0 is equal to dtr1, but got wrong result");
1249 DateTimeRule
*dtr0c
= dtr0
.clone();
1250 if (*dtr0c
!= *dtr1
|| !(*dtr0c
== *dtr1
)) {
1251 errln("FAIL: DateTimeRule dtr0c is equal to dtr1, but got wrong result");
1255 // AnnualTimeZonerule::operator=/clone
1256 AnnualTimeZoneRule
a0("a0", 5*HOUR
, 1*HOUR
, *dtr1
, 1990, AnnualTimeZoneRule::MAX_YEAR
);
1257 if (a0
== *a1
|| !(a0
!= *a1
)) {
1258 errln("FAIL: AnnualTimeZoneRule a0 is not equal to a1, but got wrong result");
1261 if (a0
!= *a1
|| !(a0
== *a1
)) {
1262 errln("FAIL: AnnualTimeZoneRule a0 is equal to a1, but got wrong result");
1264 AnnualTimeZoneRule
*a0c
= a0
.clone();
1265 if (*a0c
!= *a1
|| !(*a0c
== *a1
)) {
1266 errln("FAIL: AnnualTimeZoneRule a0c is equal to a1, but got wrong result");
1270 // AnnualTimeZoneRule::getRule
1271 if (*(a1
->getRule()) != *(a2
->getRule())) {
1272 errln("FAIL: The same DateTimeRule must be returned from AnnualTimeZoneRule a1 and a2");
1275 // AnnualTimeZoneRule::getStartYear
1276 int32_t startYear
= a1
->getStartYear();
1277 if (startYear
!= 2000) {
1278 errln((UnicodeString
)"FAIL: The start year of AnnualTimeZoneRule a1 must be 2000 - returned: " + startYear
);
1281 // AnnualTimeZoneRule::getEndYear
1282 int32_t endYear
= a1
->getEndYear();
1283 if (endYear
!= AnnualTimeZoneRule::MAX_YEAR
) {
1284 errln((UnicodeString
)"FAIL: The start year of AnnualTimeZoneRule a1 must be MAX_YEAR - returned: " + endYear
);
1286 endYear
= a3
->getEndYear();
1287 if (endYear
!= 2010) {
1288 errln((UnicodeString
)"FAIL: The start year of AnnualTimeZoneRule a3 must be 2010 - returned: " + endYear
);
1291 // AnnualTimeZone::getStartInYear
1294 b1
= a1
->getStartInYear(2005, -3*HOUR
, 0, d1
);
1295 b2
= a3
->getStartInYear(2005, -3*HOUR
, 0, d2
);
1296 if (!b1
|| !b2
|| d1
!= d2
) {
1297 errln("FAIL: AnnualTimeZoneRule::getStartInYear did not work as expected");
1299 b2
= a3
->getStartInYear(2015, -3*HOUR
, 0, d2
);
1301 errln("FAIL: AnnualTimeZoneRule::getStartInYear returned TRUE for 2015 which is out of rule range");
1304 // AnnualTimeZone::getFirstStart
1305 b1
= a1
->getFirstStart(-3*HOUR
, 0, d1
);
1306 b2
= a1
->getFirstStart(-4*HOUR
, 1*HOUR
, d2
);
1307 if (!b1
|| !b2
|| d1
!= d2
) {
1308 errln("FAIL: The same start time should be returned by getFirstStart");
1311 // AnnualTimeZone::getFinalStart
1312 b1
= a1
->getFinalStart(-3*HOUR
, 0, d1
);
1314 errln("FAIL: getFinalStart returned TRUE for a1");
1316 b1
= a1
->getStartInYear(2010, -3*HOUR
, 0, d1
);
1317 b2
= a3
->getFinalStart(-3*HOUR
, 0, d2
);
1318 if (!b1
|| !b2
|| d1
!= d2
) {
1319 errln("FAIL: Bad date is returned by getFinalStart");
1322 // AnnualTimeZone::getNextStart / getPreviousStart
1323 b1
= a1
->getNextStart(time1
, -3*HOUR
, 0, FALSE
, d1
);
1325 errln("FAIL: getNextStart returned FALSE for ai");
1327 b2
= a1
->getPreviousStart(d1
, -3*HOUR
, 0, TRUE
, d2
);
1328 if (!b2
|| d1
!= d2
) {
1329 errln("FAIL: Bad Date is returned by getPreviousStart");
1332 b1
= a3
->getNextStart(time2
, -3*HOUR
, 0, FALSE
, d1
);
1334 dataerrln("FAIL: getNextStart must return FALSE when no start time is available after the base time");
1336 b1
= a3
->getFinalStart(-3*HOUR
, 0, d1
);
1337 b2
= a3
->getPreviousStart(time2
, -3*HOUR
, 0, FALSE
, d2
);
1338 if (!b1
|| !b2
|| d1
!= d2
) {
1339 dataerrln("FAIL: getPreviousStart does not match with getFinalStart after the end year");
1342 // AnnualTimeZone::isEquavalentTo
1343 if (!a1
->isEquivalentTo(*a2
)) {
1344 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to a2, but returned FALSE");
1346 if (a1
->isEquivalentTo(*a3
)) {
1347 errln("FAIL: AnnualTimeZoneRule a1 is not equivalent to a3, but returned TRUE");
1349 if (!a1
->isEquivalentTo(*a1
)) {
1350 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to itself, but returned FALSE");
1352 if (a1
->isEquivalentTo(*t1
)) {
1353 errln("FAIL: AnnualTimeZoneRule is not equivalent to TimeArrayTimeZoneRule, but returned TRUE");
1356 // InitialTimezoneRule::operator=/clone
1357 InitialTimeZoneRule
i0("i0", 10*HOUR
, 0);
1358 if (i0
== *i1
|| !(i0
!= *i1
)) {
1359 errln("FAIL: InitialTimeZoneRule i0 is not equal to i1, but got wrong result");
1362 if (i0
!= *i1
|| !(i0
== *i1
)) {
1363 errln("FAIL: InitialTimeZoneRule i0 is equal to i1, but got wrong result");
1365 InitialTimeZoneRule
*i0c
= i0
.clone();
1366 if (*i0c
!= *i1
|| !(*i0c
== *i1
)) {
1367 errln("FAIL: InitialTimeZoneRule i0c is equal to i1, but got wrong result");
1371 // InitialTimeZoneRule::isEquivalentRule
1372 if (!i1
->isEquivalentTo(*i2
)) {
1373 errln("FAIL: InitialTimeZoneRule i1 is equivalent to i2, but returned FALSE");
1375 if (i1
->isEquivalentTo(*i3
)) {
1376 errln("FAIL: InitialTimeZoneRule i1 is not equivalent to i3, but returned TRUE");
1378 if (i1
->isEquivalentTo(*a1
)) {
1379 errln("FAIL: An InitialTimeZoneRule is not equivalent to an AnnualTimeZoneRule, but returned TRUE");
1382 // InitialTimeZoneRule::getFirstStart/getFinalStart/getNextStart/getPreviousStart
1383 b1
= i1
->getFirstStart(0, 0, d1
);
1385 errln("FAIL: InitialTimeZone::getFirstStart returned TRUE");
1387 b1
= i1
->getFinalStart(0, 0, d1
);
1389 errln("FAIL: InitialTimeZone::getFinalStart returned TRUE");
1391 b1
= i1
->getNextStart(time1
, 0, 0, FALSE
, d1
);
1393 errln("FAIL: InitialTimeZone::getNextStart returned TRUE");
1395 b1
= i1
->getPreviousStart(time1
, 0, 0, FALSE
, d1
);
1397 errln("FAIL: InitialTimeZone::getPreviousStart returned TRUE");
1400 // TimeArrayTimeZoneRule::operator=/clone
1401 TimeArrayTimeZoneRule
t0("t0", 4*HOUR
, 0, trtimes1
, 1, DateTimeRule::UTC_TIME
);
1402 if (t0
== *t1
|| !(t0
!= *t1
)) {
1403 errln("FAIL: TimeArrayTimeZoneRule t0 is not equal to t1, but got wrong result");
1406 if (t0
!= *t1
|| !(t0
== *t1
)) {
1407 errln("FAIL: TimeArrayTimeZoneRule t0 is equal to t1, but got wrong result");
1409 TimeArrayTimeZoneRule
*t0c
= t0
.clone();
1410 if (*t0c
!= *t1
|| !(*t0c
== *t1
)) {
1411 errln("FAIL: TimeArrayTimeZoneRule t0c is equal to t1, but got wrong result");
1415 // TimeArrayTimeZoneRule::countStartTimes
1416 if (t1
->countStartTimes() != 1) {
1417 errln("FAIL: Bad start time count is returned by TimeArrayTimeZoneRule::countStartTimes");
1420 // TimeArrayTimeZoneRule::getStartTimeAt
1421 b1
= t1
->getStartTimeAt(-1, d1
);
1423 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned TRUE for index -1");
1425 b1
= t1
->getStartTimeAt(0, d1
);
1426 if (!b1
|| d1
!= trtimes1
[0]) {
1427 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned incorrect result for index 0");
1429 b1
= t1
->getStartTimeAt(1, d1
);
1431 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned TRUE for index 1");
1434 // TimeArrayTimeZoneRule::getTimeType
1435 if (t1
->getTimeType() != DateTimeRule::UTC_TIME
) {
1436 errln("FAIL: TimeArrayTimeZoneRule t1 uses UTC_TIME, but different type is returned");
1438 if (t4
->getTimeType() != DateTimeRule::STANDARD_TIME
) {
1439 errln("FAIL: TimeArrayTimeZoneRule t4 uses STANDARD_TIME, but different type is returned");
1441 if (t5
->getTimeType() != DateTimeRule::WALL_TIME
) {
1442 errln("FAIL: TimeArrayTimeZoneRule t5 uses WALL_TIME, but different type is returned");
1445 // TimeArrayTimeZoneRule::getFirstStart/getFinalStart
1446 b1
= t1
->getFirstStart(0, 0, d1
);
1447 if (!b1
|| d1
!= trtimes1
[0]) {
1448 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t1");
1450 b1
= t1
->getFinalStart(0, 0, d1
);
1451 if (!b1
|| d1
!= trtimes1
[0]) {
1452 errln("FAIL: Bad final start time returned from TimeArrayTimeZoneRule t1");
1454 b1
= t4
->getFirstStart(-4*HOUR
, 1*HOUR
, d1
);
1455 if (!b1
|| d1
!= (trtimes1
[0] + 4*HOUR
)) {
1456 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t4");
1458 b1
= t5
->getFirstStart(-4*HOUR
, 1*HOUR
, d1
);
1459 if (!b1
|| d1
!= (trtimes1
[0] + 3*HOUR
)) {
1460 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t5");
1463 // TimeArrayTimeZoneRule::getNextStart/getPreviousStart
1464 b1
= t3
->getNextStart(time1
, -3*HOUR
, 1*HOUR
, FALSE
, d1
);
1466 dataerrln("FAIL: getNextStart returned TRUE after the final transition for t3");
1468 b1
= t3
->getPreviousStart(time1
, -3*HOUR
, 1*HOUR
, FALSE
, d1
);
1469 if (!b1
|| d1
!= trtimes2
[1]) {
1470 dataerrln("FAIL: Bad start time returned by getPreviousStart for t3");
1472 b2
= t3
->getPreviousStart(d1
, -3*HOUR
, 1*HOUR
, FALSE
, d2
);
1473 if (!b2
|| d2
!= trtimes2
[0]) {
1474 errln("FAIL: Bad start time returned by getPreviousStart for t3");
1477 b1
= t3
->getPreviousStart(time3
, -3*HOUR
, 1*HOUR
, FALSE
, d1
); //time3 - year 1950, no result expected
1479 errln("FAIL: getPreviousStart returned TRUE before the first transition for t3");
1482 // TimeArrayTimeZoneRule::isEquivalentTo
1483 if (!t1
->isEquivalentTo(*t2
)) {
1484 errln("FAIL: TimeArrayTimeZoneRule t1 is equivalent to t2, but returned FALSE");
1486 if (t1
->isEquivalentTo(*t3
)) {
1487 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t3, but returned TRUE");
1489 if (t1
->isEquivalentTo(*t4
)) {
1490 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t4, but returned TRUE");
1492 if (t1
->isEquivalentTo(*a1
)) {
1493 errln("FAIL: TimeArrayTimeZoneRule is not equivalent to AnnualTimeZoneRule, but returned TRUE");
1514 * API coverage test for BasicTimeZone APIs in SimpleTimeZone
1517 TimeZoneRuleTest::TestSimpleTimeZoneCoverage(void) {
1518 UDate time1
= getUTCMillis(1990, UCAL_JUNE
, 1);
1519 UDate time2
= getUTCMillis(2000, UCAL_JUNE
, 1);
1521 TimeZoneTransition tzt1
, tzt2
;
1522 UBool avail1
, avail2
;
1523 UErrorCode status
= U_ZERO_ERROR
;
1524 const TimeZoneRule
*trrules
[2];
1525 const InitialTimeZoneRule
*ir
= NULL
;
1528 // BasicTimeZone API implementation in SimpleTimeZone
1529 SimpleTimeZone
*stz1
= new SimpleTimeZone(-5*HOUR
, "GMT-5");
1531 avail1
= stz1
->getNextTransition(time1
, FALSE
, tzt1
);
1533 errln("FAIL: No transition must be returned by getNextTranstion for SimpleTimeZone with no DST rule");
1535 avail1
= stz1
->getPreviousTransition(time1
, FALSE
, tzt1
);
1537 errln("FAIL: No transition must be returned by getPreviousTransition for SimpleTimeZone with no DST rule");
1540 numTzRules
= stz1
->countTransitionRules(status
);
1541 if (U_FAILURE(status
)) {
1542 errln("FAIL: countTransitionRules failed");
1544 if (numTzRules
!= 0) {
1545 errln((UnicodeString
)"FAIL: countTransitionRules returned " + numTzRules
);
1548 stz1
->getTimeZoneRules(ir
, trrules
, numTzRules
, status
);
1549 if (U_FAILURE(status
)) {
1550 errln("FAIL: getTimeZoneRules failed");
1552 if (numTzRules
!= 0) {
1553 errln("FAIL: Incorrect transition rule count");
1555 if (ir
== NULL
|| ir
->getRawOffset() != stz1
->getRawOffset()) {
1556 errln("FAIL: Bad initial time zone rule");
1560 stz1
->setStartRule(UCAL_MARCH
, 11, 2*HOUR
, status
); // March 11
1561 stz1
->setEndRule(UCAL_NOVEMBER
, 1, UCAL_SUNDAY
, 2*HOUR
, status
); // First Sunday in November
1562 if (U_FAILURE(status
)) {
1563 errln("FAIL: Failed to set DST rules in a SimpleTimeZone");
1566 avail1
= stz1
->getNextTransition(time1
, FALSE
, tzt1
);
1568 errln("FAIL: Non-null transition must be returned by getNextTranstion for SimpleTimeZone with a DST rule");
1570 avail1
= stz1
->getPreviousTransition(time1
, FALSE
, tzt1
);
1572 errln("FAIL: Non-null transition must be returned by getPreviousTransition for SimpleTimeZone with a DST rule");
1575 numTzRules
= stz1
->countTransitionRules(status
);
1576 if (U_FAILURE(status
)) {
1577 errln("FAIL: countTransitionRules failed");
1579 if (numTzRules
!= 2) {
1580 errln((UnicodeString
)"FAIL: countTransitionRules returned " + numTzRules
);
1586 stz1
->getTimeZoneRules(ir
, trrules
, numTzRules
, status
);
1587 if (U_FAILURE(status
)) {
1588 errln("FAIL: getTimeZoneRules failed");
1590 if (numTzRules
!= 2) {
1591 errln("FAIL: Incorrect transition rule count");
1593 if (ir
== NULL
|| ir
->getRawOffset() != stz1
->getRawOffset()) {
1594 errln("FAIL: Bad initial time zone rule");
1596 if (trrules
[0] == NULL
|| trrules
[0]->getRawOffset() != stz1
->getRawOffset()) {
1597 errln("FAIL: Bad transition rule 0");
1599 if (trrules
[1] == NULL
|| trrules
[1]->getRawOffset() != stz1
->getRawOffset()) {
1600 errln("FAIL: Bad transition rule 1");
1603 // Set DST start year
1604 stz1
->setStartYear(2007);
1605 avail1
= stz1
->getPreviousTransition(time1
, FALSE
, tzt1
);
1607 errln("FAIL: No transition must be returned before 1990");
1609 avail1
= stz1
->getNextTransition(time1
, FALSE
, tzt1
); // transition after 1990-06-01
1610 avail2
= stz1
->getNextTransition(time2
, FALSE
, tzt2
); // transition after 2000-06-01
1611 if (!avail1
|| !avail2
|| tzt1
!= tzt2
) {
1612 errln("FAIL: Bad transition returned by SimpleTimeZone::getNextTransition");
1618 * API coverage test for VTimeZone
1621 TimeZoneRuleTest::TestVTimeZoneCoverage(void) {
1622 UErrorCode status
= U_ZERO_ERROR
;
1623 UnicodeString
TZID("Europe/Moscow");
1625 BasicTimeZone
*otz
= (BasicTimeZone
*)TimeZone::createTimeZone(TZID
);
1626 VTimeZone
*vtz
= VTimeZone::createVTimeZoneByID(TZID
);
1628 // getOffset(era, year, month, day, dayOfWeek, milliseconds, ec)
1629 int32_t offset1
= otz
->getOffset(GregorianCalendar::AD
, 2007, UCAL_JULY
, 1, UCAL_SUNDAY
, 0, status
);
1630 if (U_FAILURE(status
)) {
1631 errln("FAIL: getOffset(7 args) failed for otz");
1633 int32_t offset2
= vtz
->getOffset(GregorianCalendar::AD
, 2007, UCAL_JULY
, 1, UCAL_SUNDAY
, 0, status
);
1634 if (U_FAILURE(status
)) {
1635 errln("FAIL: getOffset(7 args) failed for vtz");
1637 if (offset1
!= offset2
) {
1638 errln("FAIL: getOffset(7 args) returned different results in VTimeZone and OlsonTimeZone");
1641 // getOffset(era, year, month, day, dayOfWeek, milliseconds, monthLength, ec)
1642 offset1
= otz
->getOffset(GregorianCalendar::AD
, 2007, UCAL_JULY
, 1, UCAL_SUNDAY
, 0, 31, status
);
1643 if (U_FAILURE(status
)) {
1644 errln("FAIL: getOffset(8 args) failed for otz");
1646 offset2
= vtz
->getOffset(GregorianCalendar::AD
, 2007, UCAL_JULY
, 1, UCAL_SUNDAY
, 0, 31, status
);
1647 if (U_FAILURE(status
)) {
1648 errln("FAIL: getOffset(8 args) failed for vtz");
1650 if (offset1
!= offset2
) {
1651 errln("FAIL: getOffset(8 args) returned different results in VTimeZone and OlsonTimeZone");
1655 // getOffset(date, local, rawOffset, dstOffset, ec)
1656 UDate t
= Calendar::getNow();
1657 int32_t rawOffset1
, dstSavings1
;
1658 int32_t rawOffset2
, dstSavings2
;
1660 otz
->getOffset(t
, FALSE
, rawOffset1
, dstSavings1
, status
);
1661 if (U_FAILURE(status
)) {
1662 errln("FAIL: getOffset(5 args) failed for otz");
1664 vtz
->getOffset(t
, FALSE
, rawOffset2
, dstSavings2
, status
);
1665 if (U_FAILURE(status
)) {
1666 errln("FAIL: getOffset(5 args) failed for vtz");
1668 if (rawOffset1
!= rawOffset2
|| dstSavings1
!= dstSavings2
) {
1669 errln("FAIL: getOffset(long,boolean,int[]) returned different results in VTimeZone and OlsonTimeZone");
1673 if (otz
->getRawOffset() != vtz
->getRawOffset()) {
1674 errln("FAIL: getRawOffset returned different results in VTimeZone and OlsonTimeZone");
1678 UBool inDst1
, inDst2
;
1679 inDst1
= otz
->inDaylightTime(t
, status
);
1680 if (U_FAILURE(status
)) {
1681 dataerrln("FAIL: inDaylightTime failed for otz: %s", u_errorName(status
));
1683 inDst2
= vtz
->inDaylightTime(t
, status
);
1684 if (U_FAILURE(status
)) {
1685 dataerrln("FAIL: inDaylightTime failed for vtz: %s", u_errorName(status
));
1687 if (inDst1
!= inDst2
) {
1688 errln("FAIL: inDaylightTime returned different results in VTimeZone and OlsonTimeZone");
1692 if (otz
->useDaylightTime() != vtz
->useDaylightTime()) {
1693 errln("FAIL: useDaylightTime returned different results in VTimeZone and OlsonTimeZone");
1697 const int32_t RAW
= -10*HOUR
;
1698 VTimeZone
*tmpvtz
= (VTimeZone
*)vtz
->clone();
1699 tmpvtz
->setRawOffset(RAW
);
1700 if (tmpvtz
->getRawOffset() != RAW
) {
1701 logln("setRawOffset is implemented in VTimeZone");
1705 UBool bSame
= otz
->hasSameRules(*vtz
);
1706 logln((UnicodeString
)"OlsonTimeZone::hasSameRules(VTimeZone) should return FALSE always for now - actual: " + bSame
);
1708 // getTZURL/setTZURL
1709 UnicodeString
TZURL("http://icu-project.org/timezone");
1711 if (vtz
->getTZURL(url
)) {
1712 errln("FAIL: getTZURL returned TRUE");
1714 vtz
->setTZURL(TZURL
);
1715 if (!vtz
->getTZURL(url
) || url
!= TZURL
) {
1716 errln("FAIL: URL returned by getTZURL does not match the one set by setTZURL");
1719 // getLastModified/setLastModified
1721 if (vtz
->getLastModified(lastmod
)) {
1722 errln("FAIL: getLastModified returned TRUE");
1724 vtz
->setLastModified(t
);
1725 if (!vtz
->getLastModified(lastmod
) || lastmod
!= t
) {
1726 errln("FAIL: Date returned by getLastModified does not match the one set by setLastModified");
1729 // getNextTransition/getPreviousTransition
1730 UDate base
= getUTCMillis(2007, UCAL_JULY
, 1);
1731 TimeZoneTransition tzt1
, tzt2
;
1732 UBool btr1
= otz
->getNextTransition(base
, TRUE
, tzt1
);
1733 UBool btr2
= vtz
->getNextTransition(base
, TRUE
, tzt2
);
1734 if (!btr1
|| !btr2
|| tzt1
!= tzt2
) {
1735 dataerrln("FAIL: getNextTransition returned different results in VTimeZone and OlsonTimeZone");
1737 btr1
= otz
->getPreviousTransition(base
, FALSE
, tzt1
);
1738 btr2
= vtz
->getPreviousTransition(base
, FALSE
, tzt2
);
1739 if (!btr1
|| !btr2
|| tzt1
!= tzt2
) {
1740 dataerrln("FAIL: getPreviousTransition returned different results in VTimeZone and OlsonTimeZone");
1743 // TimeZoneTransition constructor/clone
1744 TimeZoneTransition
*tzt1c
= tzt1
.clone();
1745 if (*tzt1c
!= tzt1
|| !(*tzt1c
== tzt1
)) {
1746 errln("FAIL: TimeZoneTransition tzt1c is equal to tzt1, but got wrong result");
1749 TimeZoneTransition
tzt3(tzt1
);
1750 if (tzt3
!= tzt1
|| !(tzt3
== tzt1
)) {
1751 errln("FAIL: TimeZoneTransition tzt3 is equal to tzt1, but got wrong result");
1754 // hasEquivalentTransitions
1755 UDate time1
= getUTCMillis(1950, UCAL_JANUARY
, 1);
1756 UDate time2
= getUTCMillis(2020, UCAL_JANUARY
, 1);
1757 UBool equiv
= vtz
->hasEquivalentTransitions(*otz
, time1
, time2
, FALSE
, status
);
1758 if (U_FAILURE(status
)) {
1759 dataerrln("FAIL: hasEquivalentTransitions failed for vtz/otz: %s", u_errorName(status
));
1762 dataerrln("FAIL: hasEquivalentTransitons returned false for the same time zone");
1765 // operator=/operator==/operator!=
1766 VTimeZone
*vtz1
= VTimeZone::createVTimeZoneByID("America/Los_Angeles");
1767 if (*vtz1
== *vtz
|| !(*vtz1
!= *vtz
)) {
1768 errln("FAIL: VTimeZone vtz1 is not equal to vtz, but got wrong result");
1771 if (*vtz1
!= *vtz
|| !(*vtz1
== *vtz
)) {
1772 errln("FAIL: VTimeZone vtz1 is equal to vtz, but got wrong result");
1775 // Creation from BasicTimeZone
1777 status
= U_ZERO_ERROR
;
1778 VTimeZone
*vtzFromBasic
= NULL
;
1779 SimpleTimeZone
*simpleTZ
= new SimpleTimeZone(28800000, "Asia/Singapore");
1780 simpleTZ
->setStartYear(1970);
1781 simpleTZ
->setStartRule(0, // month
1785 simpleTZ
->setEndRule(1, 1, 0, status
);
1786 if (U_FAILURE(status
)) {
1787 errln("File %s, line %d, failed with status = %s", __FILE__
, __LINE__
, u_errorName(status
));
1788 goto end_basic_tz_test
;
1790 vtzFromBasic
= VTimeZone::createVTimeZoneFromBasicTimeZone(*simpleTZ
, status
);
1791 if (U_FAILURE(status
) || vtzFromBasic
== NULL
) {
1792 dataerrln("File %s, line %d, failed with status = %s", __FILE__
, __LINE__
, u_errorName(status
));
1793 goto end_basic_tz_test
;
1796 // delete the source time zone, to make sure there are no dependencies on it.
1799 // Create another simple time zone w the same rules, and check that it is the
1800 // same as the test VTimeZone created above.
1802 SimpleTimeZone
simpleTZ2(28800000, "Asia/Singapore");
1803 simpleTZ2
.setStartYear(1970);
1804 simpleTZ2
.setStartRule(0, // month
1808 simpleTZ2
.setEndRule(1, 1, 0, status
);
1809 if (U_FAILURE(status
)) {
1810 errln("File %s, line %d, failed with status = %s", __FILE__
, __LINE__
, u_errorName(status
));
1811 goto end_basic_tz_test
;
1813 if (vtzFromBasic
->hasSameRules(simpleTZ2
) == FALSE
) {
1814 errln("File %s, line %d, failed hasSameRules() ", __FILE__
, __LINE__
);
1815 goto end_basic_tz_test
;
1819 delete vtzFromBasic
;
1829 TimeZoneRuleTest::TestVTimeZoneParse(void) {
1830 UErrorCode status
= U_ZERO_ERROR
;
1832 // Trying to create VTimeZone from empty data
1833 UnicodeString emptyData
;
1834 VTimeZone
*empty
= VTimeZone::createVTimeZone(emptyData
, status
);
1835 if (U_SUCCESS(status
) || empty
!= NULL
) {
1837 errln("FAIL: Non-null VTimeZone is returned for empty VTIMEZONE data");
1839 status
= U_ZERO_ERROR
;
1841 // Create VTimeZone for Asia/Tokyo
1842 UnicodeString
asiaTokyoID("Asia/Tokyo");
1843 static const UChar asiaTokyo
[] = {
1844 /* "BEGIN:VTIMEZONE\x0D\x0A" */
1845 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
1846 /* "TZID:Asia\x0D\x0A" */
1847 0x54,0x5A,0x49,0x44,0x3A,0x41,0x73,0x69,0x61,0x0D,0x0A,
1848 /* "\x09/Tokyo\x0D\x0A" */
1849 0x09,0x2F,0x54,0x6F,0x6B,0x79,0x6F,0x0D,0x0A,
1850 /* "BEGIN:STANDARD\x0D\x0A" */
1851 0x42,0x45,0x47,0x49,0x4E,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1852 /* "TZOFFSETFROM:+0900\x0D\x0A" */
1853 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2B,0x30,0x39,0x30,0x30,0x0D,0x0A,
1854 /* "TZOFFSETTO:+0900\x0D\x0A" */
1855 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2B,0x30,0x39,0x30,0x30,0x0D,0x0A,
1856 /* "TZNAME:JST\x0D\x0A" */
1857 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x4A,0x53,0x54,0x0D,0x0A,
1858 /* "DTSTART:19700101\x0D\x0A" */
1859 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3A,0x31,0x39,0x37,0x30,0x30,0x31,0x30,0x31,0x0D,0x0A,
1860 /* " T000000\x0D\x0A" */
1861 0x20,0x54,0x30,0x30,0x30,0x30,0x30,0x30,0x0D,0x0A,
1862 /* "END:STANDARD\x0D\x0A" */
1863 0x45,0x4E,0x44,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1864 /* "END:VTIMEZONE" */
1865 0x45,0x4E,0x44,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,
1868 VTimeZone
*tokyo
= VTimeZone::createVTimeZone(asiaTokyo
, status
);
1869 if (U_FAILURE(status
) || tokyo
== NULL
) {
1870 errln("FAIL: Failed to create a VTimeZone tokyo");
1875 if (tzid
!= asiaTokyoID
) {
1876 errln((UnicodeString
)"FAIL: Invalid TZID: " + tzid
);
1878 // Make sure offsets are correct
1879 int32_t rawOffset
, dstSavings
;
1880 tokyo
->getOffset(Calendar::getNow(), FALSE
, rawOffset
, dstSavings
, status
);
1881 if (U_FAILURE(status
)) {
1882 errln("FAIL: getOffset failed for tokyo");
1884 if (rawOffset
!= 9*HOUR
|| dstSavings
!= 0) {
1885 errln("FAIL: Bad offsets returned by a VTimeZone created for Tokyo");
1890 // Create VTimeZone from VTIMEZONE data
1891 static const UChar fooData
[] = {
1892 /* "BEGIN:VCALENDAR\x0D\x0A" */
1893 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x43,0x41,0x4C,0x45,0x4E,0x44,0x41,0x52,0x0D,0x0A,
1894 /* "BEGIN:VTIMEZONE\x0D\x0A" */
1895 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
1896 /* "TZID:FOO\x0D\x0A" */
1897 0x54,0x5A,0x49,0x44,0x3A,0x46,0x4F,0x4F,0x0D,0x0A,
1898 /* "BEGIN:STANDARD\x0D\x0A" */
1899 0x42,0x45,0x47,0x49,0x4E,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1900 /* "TZOFFSETFROM:-0700\x0D\x0A" */
1901 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2D,0x30,0x37,0x30,0x30,0x0D,0x0A,
1902 /* "TZOFFSETTO:-0800\x0D\x0A" */
1903 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2D,0x30,0x38,0x30,0x30,0x0D,0x0A,
1904 /* "TZNAME:FST\x0D\x0A" */
1905 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x46,0x53,0x54,0x0D,0x0A,
1906 /* "DTSTART:20071010T010000\x0D\x0A" */
1907 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,
1908 /* "RRULE:FREQ=YEARLY;BYDAY=WE;BYMONTHDAY=10,11,12,13,14,15,16;BYMONTH=10\x0D\x0A" */
1909 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,
1910 /* "END:STANDARD\x0D\x0A" */
1911 0x45,0x4E,0x44,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
1912 /* "BEGIN:DAYLIGHT\x0D\x0A" */
1913 0x42,0x45,0x47,0x49,0x4E,0x3A,0x44,0x41,0x59,0x4C,0x49,0x47,0x48,0x54,0x0D,0x0A,
1914 /* "TZOFFSETFROM:-0800\x0D\x0A" */
1915 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2D,0x30,0x38,0x30,0x30,0x0D,0x0A,
1916 /* "TZOFFSETTO:-0700\x0D\x0A" */
1917 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2D,0x30,0x37,0x30,0x30,0x0D,0x0A,
1918 /* "TZNAME:FDT\x0D\x0A" */
1919 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x46,0x44,0x54,0x0D,0x0A,
1920 /* "DTSTART:20070415T010000\x0D\x0A" */
1921 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,
1922 /* "RRULE:FREQ=YEARLY;BYMONTHDAY=15;BYMONTH=4\x0D\x0A" */
1923 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,
1924 /* "END:DAYLIGHT\x0D\x0A" */
1925 0x45,0x4E,0x44,0x3A,0x44,0x41,0x59,0x4C,0x49,0x47,0x48,0x54,0x0D,0x0A,
1926 /* "END:VTIMEZONE\x0D\x0A" */
1927 0x45,0x4E,0x44,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
1928 /* "END:VCALENDAR" */
1929 0x45,0x4E,0x44,0x3A,0x56,0x43,0x41,0x4C,0x45,0x4E,0x44,0x41,0x52,
1933 VTimeZone
*foo
= VTimeZone::createVTimeZone(fooData
, status
);
1934 if (U_FAILURE(status
) || foo
== NULL
) {
1935 errln("FAIL: Failed to create a VTimeZone foo");
1937 // Write VTIMEZONE data
1938 UnicodeString fooData2
;
1939 foo
->write(getUTCMillis(2005, UCAL_JANUARY
, 1), fooData2
, status
);
1940 if (U_FAILURE(status
)) {
1941 errln("FAIL: Failed to write VTIMEZONE data for foo");
1949 TimeZoneRuleTest::TestT6216(void) {
1950 // Test case in #6216
1951 static const UChar tokyoTZ
[] = {
1952 /* "BEGIN:VCALENDAR\r\n" */
1953 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
1954 /* "VERSION:2.0\r\n" */
1955 0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x3a,0x32,0x2e,0x30,0x0d,0x0a,
1956 /* "PRODID:-//PYVOBJECT//NONSGML Version 1//EN\r\n" */
1957 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,
1958 /* "BEGIN:VTIMEZONE\r\n" */
1959 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
1960 /* "TZID:Asia/Tokyo\r\n" */
1961 0x54,0x5a,0x49,0x44,0x3a,0x41,0x73,0x69,0x61,0x2f,0x54,0x6f,0x6b,0x79,0x6f,0x0d,0x0a,
1962 /* "BEGIN:STANDARD\r\n" */
1963 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
1964 /* "DTSTART:20000101T000000\r\n" */
1965 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,
1966 /* "RRULE:FREQ=YEARLY;BYMONTH=1\r\n" */
1967 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,
1968 /* "TZNAME:Asia/Tokyo\r\n" */
1969 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x41,0x73,0x69,0x61,0x2f,0x54,0x6f,0x6b,0x79,0x6f,0x0d,0x0a,
1970 /* "TZOFFSETFROM:+0900\r\n" */
1971 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2b,0x30,0x39,0x30,0x30,0x0d,0x0a,
1972 /* "TZOFFSETTO:+0900\r\n" */
1973 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2b,0x30,0x39,0x30,0x30,0x0d,0x0a,
1974 /* "END:STANDARD\r\n" */
1975 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
1976 /* "END:VTIMEZONE\r\n" */
1977 0x45,0x4e,0x44,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
1978 /* "END:VCALENDAR" */
1979 0x45,0x4e,0x44,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
1982 // Single final rule, overlapping with another
1983 static const UChar finalOverlap
[] = {
1984 /* "BEGIN:VCALENDAR\r\n" */
1985 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
1986 /* "BEGIN:VTIMEZONE\r\n" */
1987 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
1988 /* "TZID:FinalOverlap\r\n" */
1989 0x54,0x5a,0x49,0x44,0x3a,0x46,0x69,0x6e,0x61,0x6c,0x4f,0x76,0x65,0x72,0x6c,0x61,0x70,0x0d,0x0a,
1990 /* "BEGIN:STANDARD\r\n" */
1991 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
1992 /* "TZOFFSETFROM:-0200\r\n" */
1993 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a,
1994 /* "TZOFFSETTO:-0300\r\n" */
1995 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a,
1996 /* "TZNAME:STD\r\n" */
1997 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x53,0x54,0x44,0x0d,0x0a,
1998 /* "DTSTART:20001029T020000\r\n" */
1999 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,
2000 /* "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" */
2001 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,
2002 /* "END:STANDARD\r\n" */
2003 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
2004 /* "BEGIN:DAYLIGHT\r\n" */
2005 0x42,0x45,0x47,0x49,0x4e,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a,
2006 /* "TZOFFSETFROM:-0300\r\n" */
2007 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a,
2008 /* "TZOFFSETTO:-0200\r\n" */
2009 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a,
2010 /* "TZNAME:DST\r\n" */
2011 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x44,0x53,0x54,0x0d,0x0a,
2012 /* "DTSTART:19990404T020000\r\n" */
2013 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,
2014 /* "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" */
2015 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,
2016 /* "END:DAYLIGHT\r\n" */
2017 0x45,0x4e,0x44,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a,
2018 /* "END:VTIMEZONE\r\n" */
2019 0x45,0x4e,0x44,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
2020 /* "END:VCALENDAR" */
2021 0x45,0x4e,0x44,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
2024 // Single final rule, no overlapping with another
2025 static const UChar finalNonOverlap
[] = {
2026 /* "BEGIN:VCALENDAR\r\n" */
2027 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
2028 /* "BEGIN:VTIMEZONE\r\n" */
2029 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
2030 /* "TZID:FinalNonOverlap\r\n" */
2031 0x54,0x5a,0x49,0x44,0x3a,0x46,0x69,0x6e,0x61,0x6c,0x4e,0x6f,0x6e,0x4f,0x76,0x65,0x72,0x6c,0x61,0x70,0x0d,0x0a,
2032 /* "BEGIN:STANDARD\r\n" */
2033 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
2034 /* "TZOFFSETFROM:-0200\r\n" */
2035 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a,
2036 /* "TZOFFSETTO:-0300\r\n" */
2037 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a,
2038 /* "TZNAME:STD\r\n" */
2039 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x53,0x54,0x44,0x0d,0x0a,
2040 /* "DTSTART:20001029T020000\r\n" */
2041 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,
2042 /* "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10;UNTIL=20041031T040000Z\r\n" */
2043 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,
2044 /* "END:STANDARD\r\n" */
2045 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
2046 /* "BEGIN:DAYLIGHT\r\n" */
2047 0x42,0x45,0x47,0x49,0x4e,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a,
2048 /* "TZOFFSETFROM:-0300\r\n" */
2049 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a,
2050 /* "TZOFFSETTO:-0200\r\n" */
2051 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a,
2052 /* "TZNAME:DST\r\n" */
2053 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x44,0x53,0x54,0x0d,0x0a,
2054 /* "DTSTART:19990404T020000\r\n" */
2055 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,
2056 /* "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" */
2057 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,
2058 /* "END:DAYLIGHT\r\n" */
2059 0x45,0x4e,0x44,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a,
2060 /* "BEGIN:STANDARD\r\n" */
2061 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
2062 /* "TZOFFSETFROM:-0200\r\n" */
2063 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a,
2064 /* "TZOFFSETTO:-0300\r\n" */
2065 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a,
2066 /* "TZNAME:STDFINAL\r\n" */
2067 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x53,0x54,0x44,0x46,0x49,0x4e,0x41,0x4c,0x0d,0x0a,
2068 /* "DTSTART:20071028T020000\r\n" */
2069 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,
2070 /* "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" */
2071 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,
2072 /* "END:STANDARD\r\n" */
2073 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a,
2074 /* "END:VTIMEZONE\r\n" */
2075 0x45,0x4e,0x44,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a,
2076 /* "END:VCALENDAR" */
2077 0x45,0x4e,0x44,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a,
2081 static const int32_t TestDates
[][3] = {
2082 {1995, UCAL_JANUARY
, 1},
2083 {1995, UCAL_JULY
, 1},
2084 {2000, UCAL_JANUARY
, 1},
2085 {2000, UCAL_JULY
, 1},
2086 {2005, UCAL_JANUARY
, 1},
2087 {2005, UCAL_JULY
, 1},
2088 {2010, UCAL_JANUARY
, 1},
2089 {2010, UCAL_JULY
, 1},
2093 /*static*/ const UnicodeString TestZones
[] = {
2094 UnicodeString(tokyoTZ
),
2095 UnicodeString(finalOverlap
),
2096 UnicodeString(finalNonOverlap
),
2100 int32_t Expected
[][8] = {
2101 // JAN90 JUL90 JAN00 JUL00 JAN05 JUL05 JAN10 JUL10
2102 { 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000},
2103 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000},
2104 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000}
2110 UDate times
[UPRV_LENGTHOF(TestDates
)];
2113 UErrorCode status
= U_ZERO_ERROR
;
2114 TimeZone
*utc
= TimeZone::createTimeZone("Etc/GMT");
2115 GregorianCalendar
cal(utc
, status
);
2116 if (U_FAILURE(status
)) {
2117 dataerrln("FAIL: Failed to creat a GregorianCalendar: %s", u_errorName(status
));
2120 for (i
= 0; TestDates
[i
][2] != 0; i
++) {
2122 cal
.set(TestDates
[i
][0], TestDates
[i
][1], TestDates
[i
][2]);
2123 times
[i
] = cal
.getTime(status
);
2124 if (U_FAILURE(status
)) {
2125 errln("FAIL: getTime failed");
2132 for (i
= 0; !TestZones
[i
].isEmpty(); i
++) {
2133 VTimeZone
*vtz
= VTimeZone::createVTimeZone(TestZones
[i
], status
);
2134 if (U_FAILURE(status
)) {
2135 errln("FAIL: failed to create VTimeZone");
2138 for (j
= 0; j
< numTimes
; j
++) {
2140 status
= U_ZERO_ERROR
;
2141 vtz
->getOffset(times
[j
], FALSE
, raw
, dst
, status
);
2142 if (U_FAILURE(status
)) {
2143 errln((UnicodeString
)"FAIL: getOffset failed for time zone " + i
+ " at " + times
[j
]);
2145 int32_t offset
= raw
+ dst
;
2146 if (offset
!= Expected
[i
][j
]) {
2147 errln((UnicodeString
)"FAIL: Invalid offset at time(" + times
[j
] + "):" + offset
+ " Expected:" + Expected
[i
][j
]);
2155 TimeZoneRuleTest::TestT6669(void) {
2156 UErrorCode status
= U_ZERO_ERROR
;
2157 SimpleTimeZone
stz(0, "CustomID", UCAL_JANUARY
, 1, UCAL_SUNDAY
, 0, UCAL_JULY
, 1, UCAL_SUNDAY
, 0, status
);
2158 if (U_FAILURE(status
)) {
2159 errln("FAIL: Failed to creat a SimpleTimeZone");
2163 UDate t
= 1230681600000.0; //2008-12-31T00:00:00
2164 UDate expectedNext
= 1231027200000.0; //2009-01-04T00:00:00
2165 UDate expectedPrev
= 1215298800000.0; //2008-07-06T00:00:00
2167 TimeZoneTransition tzt
;
2168 UBool avail
= stz
.getNextTransition(t
, FALSE
, tzt
);
2170 errln("FAIL: No transition returned by getNextTransition.");
2171 } else if (tzt
.getTime() != expectedNext
) {
2172 errln((UnicodeString
)"FAIL: Wrong transition time returned by getNextTransition - "
2173 + tzt
.getTime() + " Expected: " + expectedNext
);
2176 avail
= stz
.getPreviousTransition(t
, TRUE
, tzt
);
2178 errln("FAIL: No transition returned by getPreviousTransition.");
2179 } else if (tzt
.getTime() != expectedPrev
) {
2180 errln((UnicodeString
)"FAIL: Wrong transition time returned by getPreviousTransition - "
2181 + tzt
.getTime() + " Expected: " + expectedPrev
);
2186 TimeZoneRuleTest::TestVTimeZoneWrapper(void) {
2190 UChar
* data
= NULL
;
2194 UDate base
= 1231027200000.0; //2009-01-04T00:00:00
2197 const char *name
= "Test Initial";
2211 uprv_memset(uname
, 0, sizeof(uname
));
2212 u_uastrcpy(uname
, name
);
2215 ir1
= izrule_open(uname
, 13, 2*HOUR
, 0);
2216 ir2
= izrule_clone(ir1
);
2219 b
= izrule_equals(ir1
, ir2
);
2220 b
= izrule_isEquivalentTo(ir1
, ir2
);
2223 izrule_getName(ir1
, data
, length
);
2224 i
= izrule_getRawOffset(ir1
);
2225 i
= izrule_getDSTSavings(ir1
);
2227 b
= izrule_getFirstStart(ir1
, 2*HOUR
, 0, result
);
2228 b
= izrule_getFinalStart(ir1
, 2*HOUR
, 0, result
);
2229 b
= izrule_getNextStart(ir1
, base
, 2*HOUR
, 0, true, result
);
2230 b
= izrule_getPreviousStart(ir1
, base
, 2*HOUR
, 0, true, result
);
2233 cid1
= izrule_getStaticClassID(ir1
);
2234 cid2
= izrule_getDynamicClassID(ir1
);
2237 zt1
= ztrans_open(base
, ir1
, ir2
);
2238 zt2
= ztrans_clone(zt1
);
2239 zt2
= ztrans_openEmpty();
2242 b
= ztrans_equals(zt1
, zt2
);
2245 result
= ztrans_getTime(zt1
);
2246 ztrans_setTime(zt1
, result
);
2248 r
= (ZRule
*)ztrans_getFrom(zt1
);
2249 ztrans_setFrom(zt1
, (void*)ir1
);
2250 ztrans_adoptFrom(zt1
, (void*)ir1
);
2252 r
= (ZRule
*)ztrans_getTo(zt1
);
2253 ztrans_setTo(zt1
, (void*)ir2
);
2254 ztrans_adoptTo(zt1
, (void*)ir2
);
2257 cid1
= ztrans_getStaticClassID(zt1
);
2258 cid2
= ztrans_getDynamicClassID(zt2
);
2261 v1
= vzone_openID((UChar
*)"America/Chicago", sizeof("America/Chicago"));
2262 v2
= vzone_clone(v1
);
2263 //v2 = vzone_openData(const UChar* vtzdata, int32_t vtzdataLength, UErrorCode& status);
2266 b
= vzone_equals(v1
, v2
);
2267 b
= vzone_hasSameRules(v1
, v2
);
2270 b
= vzone_getTZURL(v1
, data
, length
);
2271 vzone_setTZURL(v1
, data
, length
);
2273 b
= vzone_getLastModified(v1
, result
);
2274 vzone_setLastModified(v1
, result
);
2277 vzone_write(v1
, data
, length
, status
);
2278 vzone_writeFromStart(v1
, result
, data
, length
, status
);
2279 vzone_writeSimple(v1
, result
, data
, length
, status
);
2281 // test more accessors
2282 i
= vzone_getRawOffset(v1
);
2283 vzone_setRawOffset(v1
, i
);
2285 b
= vzone_useDaylightTime(v1
);
2286 b
= vzone_inDaylightTime(v1
, result
, status
);
2288 b
= vzone_getNextTransition(v1
, result
, false, zt1
);
2289 b
= vzone_getPreviousTransition(v1
, result
, false, zt1
);
2290 i
= vzone_countTransitionRules(v1
, status
);
2292 cid1
= vzone_getStaticClassID(v1
);
2293 cid2
= vzone_getDynamicClassID(v1
);
2303 //----------- private test helpers -------------------------------------------------
2306 TimeZoneRuleTest::getUTCMillis(int32_t y
, int32_t m
, int32_t d
,
2307 int32_t hr
, int32_t min
, int32_t sec
, int32_t msec
) {
2308 UErrorCode status
= U_ZERO_ERROR
;
2309 const TimeZone
*tz
= TimeZone::getGMT();
2310 Calendar
*cal
= Calendar::createInstance(*tz
, status
);
2311 if (U_FAILURE(status
)) {
2313 dataerrln("FAIL: Calendar::createInstance failed: %s", u_errorName(status
));
2316 cal
->set(y
, m
, d
, hr
, min
, sec
);
2317 cal
->set(UCAL_MILLISECOND
, msec
);
2318 UDate utc
= cal
->getTime(status
);
2319 if (U_FAILURE(status
)) {
2321 errln("FAIL: Calendar::getTime failed");
2329 * Check if a time shift really happens on each transition returned by getNextTransition or
2330 * getPreviousTransition in the specified time range
2333 TimeZoneRuleTest::verifyTransitions(BasicTimeZone
& icutz
, UDate start
, UDate end
) {
2334 UErrorCode status
= U_ZERO_ERROR
;
2336 int32_t raw
, dst
, raw0
, dst0
;
2337 TimeZoneTransition tzt
, tzt0
;
2345 avail
= icutz
.getNextTransition(time
, FALSE
, tzt
);
2349 time
= tzt
.getTime();
2353 icutz
.getOffset(time
, FALSE
, raw
, dst
, status
);
2354 icutz
.getOffset(time
- 1, FALSE
, raw0
, dst0
, status
);
2355 if (U_FAILURE(status
)) {
2356 errln("FAIL: Error in getOffset");
2360 if (raw
== raw0
&& dst
== dst0
) {
2361 errln((UnicodeString
)"FAIL: False transition returned by getNextTransition for "
2362 + icutz
.getID(tzid
) + " at " + dateToString(time
));
2365 (tzt0
.getTo()->getRawOffset() != tzt
.getFrom()->getRawOffset()
2366 || tzt0
.getTo()->getDSTSavings() != tzt
.getFrom()->getDSTSavings())) {
2367 errln((UnicodeString
)"FAIL: TO rule of the previous transition does not match FROM rule of this transtion at "
2368 + dateToString(time
) + " for " + icutz
.getID(tzid
));
2378 avail
= icutz
.getPreviousTransition(time
, FALSE
, tzt
);
2382 time
= tzt
.getTime();
2383 if (time
<= start
) {
2386 icutz
.getOffset(time
, FALSE
, raw
, dst
, status
);
2387 icutz
.getOffset(time
- 1, FALSE
, raw0
, dst0
, status
);
2388 if (U_FAILURE(status
)) {
2389 errln("FAIL: Error in getOffset");
2393 if (raw
== raw0
&& dst
== dst0
) {
2394 errln((UnicodeString
)"FAIL: False transition returned by getPreviousTransition for "
2395 + icutz
.getID(tzid
) + " at " + dateToString(time
));
2399 (tzt0
.getFrom()->getRawOffset() != tzt
.getTo()->getRawOffset()
2400 || tzt0
.getFrom()->getDSTSavings() != tzt
.getTo()->getDSTSavings())) {
2401 errln((UnicodeString
)"FAIL: TO rule of the next transition does not match FROM rule in this transtion at "
2402 + dateToString(time
) + " for " + icutz
.getID(tzid
));
2410 * Compare all time transitions in 2 time zones in the specified time range in ascending order
2413 TimeZoneRuleTest::compareTransitionsAscending(BasicTimeZone
& z1
, BasicTimeZone
& z2
,
2414 UDate start
, UDate end
, UBool inclusive
) {
2415 UnicodeString zid1
, zid2
;
2416 TimeZoneTransition tzt1
, tzt2
;
2417 UBool avail1
, avail2
;
2418 UBool inRange1
, inRange2
;
2425 avail1
= z1
.getNextTransition(time
, inclusive
, tzt1
);
2426 avail2
= z2
.getNextTransition(time
, inclusive
, tzt2
);
2428 inRange1
= inRange2
= FALSE
;
2430 if (tzt1
.getTime() < end
|| (inclusive
&& tzt1
.getTime() == end
)) {
2435 if (tzt2
.getTime() < end
|| (inclusive
&& tzt2
.getTime() == end
)) {
2439 if (!inRange1
&& !inRange2
) {
2440 // No more transition in the range
2444 errln((UnicodeString
)"FAIL: " + zid1
+ " does not have any transitions after "
2445 + dateToString(time
) + " before " + dateToString(end
));
2449 errln((UnicodeString
)"FAIL: " + zid2
+ " does not have any transitions after "
2450 + dateToString(time
) + " before " + dateToString(end
));
2453 if (tzt1
.getTime() != tzt2
.getTime()) {
2454 errln((UnicodeString
)"FAIL: First transition after " + dateToString(time
) + " "
2455 + zid1
+ "[" + dateToString(tzt1
.getTime()) + "] "
2456 + zid2
+ "[" + dateToString(tzt2
.getTime()) + "]");
2459 time
= tzt1
.getTime();
2467 * Compare all time transitions in 2 time zones in the specified time range in descending order
2470 TimeZoneRuleTest::compareTransitionsDescending(BasicTimeZone
& z1
, BasicTimeZone
& z2
,
2471 UDate start
, UDate end
, UBool inclusive
) {
2472 UnicodeString zid1
, zid2
;
2473 TimeZoneTransition tzt1
, tzt2
;
2474 UBool avail1
, avail2
;
2475 UBool inRange1
, inRange2
;
2482 avail1
= z1
.getPreviousTransition(time
, inclusive
, tzt1
);
2483 avail2
= z2
.getPreviousTransition(time
, inclusive
, tzt2
);
2485 inRange1
= inRange2
= FALSE
;
2487 if (tzt1
.getTime() > start
|| (inclusive
&& tzt1
.getTime() == start
)) {
2492 if (tzt2
.getTime() > start
|| (inclusive
&& tzt2
.getTime() == start
)) {
2496 if (!inRange1
&& !inRange2
) {
2497 // No more transition in the range
2501 errln((UnicodeString
)"FAIL: " + zid1
+ " does not have any transitions before "
2502 + dateToString(time
) + " after " + dateToString(start
));
2506 errln((UnicodeString
)"FAIL: " + zid2
+ " does not have any transitions before "
2507 + dateToString(time
) + " after " + dateToString(start
));
2510 if (tzt1
.getTime() != tzt2
.getTime()) {
2511 errln((UnicodeString
)"FAIL: Last transition before " + dateToString(time
) + " "
2512 + zid1
+ "[" + dateToString(tzt1
.getTime()) + "] "
2513 + zid2
+ "[" + dateToString(tzt2
.getTime()) + "]");
2516 time
= tzt1
.getTime();
2523 // Slightly modified version of BasicTimeZone::hasEquivalentTransitions.
2524 // This version returns TRUE if transition time delta is within the given
2526 static UBool
hasEquivalentTransitions(/*const*/ BasicTimeZone
& tz1
, /*const*/BasicTimeZone
& tz2
,
2527 UDate start
, UDate end
,
2528 UBool ignoreDstAmount
, int32_t maxTransitionTimeDelta
,
2529 UErrorCode
& status
) {
2530 if (U_FAILURE(status
)) {
2533 if (tz1
.hasSameRules(tz2
)) {
2536 // Check the offsets at the start time
2537 int32_t raw1
, raw2
, dst1
, dst2
;
2538 tz1
.getOffset(start
, FALSE
, raw1
, dst1
, status
);
2539 if (U_FAILURE(status
)) {
2542 tz2
.getOffset(start
, FALSE
, raw2
, dst2
, status
);
2543 if (U_FAILURE(status
)) {
2546 if (ignoreDstAmount
) {
2547 if ((raw1
+ dst1
!= raw2
+ dst2
)
2548 || (dst1
!= 0 && dst2
== 0)
2549 || (dst1
== 0 && dst2
!= 0)) {
2553 if (raw1
!= raw2
|| dst1
!= dst2
) {
2557 // Check transitions in the range
2559 TimeZoneTransition tr1
, tr2
;
2561 UBool avail1
= tz1
.getNextTransition(time
, FALSE
, tr1
);
2562 UBool avail2
= tz2
.getNextTransition(time
, FALSE
, tr2
);
2564 if (ignoreDstAmount
) {
2565 // Skip a transition which only differ the amount of DST savings
2568 && tr1
.getTime() <= end
2569 && (tr1
.getFrom()->getRawOffset() + tr1
.getFrom()->getDSTSavings()
2570 == tr1
.getTo()->getRawOffset() + tr1
.getTo()->getDSTSavings())
2571 && (tr1
.getFrom()->getDSTSavings() != 0 && tr1
.getTo()->getDSTSavings() != 0)) {
2572 tz1
.getNextTransition(tr1
.getTime(), FALSE
, tr1
);
2579 && tr2
.getTime() <= end
2580 && (tr2
.getFrom()->getRawOffset() + tr2
.getFrom()->getDSTSavings()
2581 == tr2
.getTo()->getRawOffset() + tr2
.getTo()->getDSTSavings())
2582 && (tr2
.getFrom()->getDSTSavings() != 0 && tr2
.getTo()->getDSTSavings() != 0)) {
2583 tz2
.getNextTransition(tr2
.getTime(), FALSE
, tr2
);
2590 UBool inRange1
= (avail1
&& tr1
.getTime() <= end
);
2591 UBool inRange2
= (avail2
&& tr2
.getTime() <= end
);
2592 if (!inRange1
&& !inRange2
) {
2593 // No more transition in the range
2596 if (!inRange1
|| !inRange2
) {
2599 double delta
= tr1
.getTime() >= tr2
.getTime() ? tr1
.getTime() - tr2
.getTime() : tr2
.getTime() - tr1
.getTime();
2600 if (delta
> (double)maxTransitionTimeDelta
) {
2603 if (ignoreDstAmount
) {
2604 if (tr1
.getTo()->getRawOffset() + tr1
.getTo()->getDSTSavings()
2605 != tr2
.getTo()->getRawOffset() + tr2
.getTo()->getDSTSavings()
2606 || (tr1
.getTo()->getDSTSavings() != 0 && tr2
.getTo()->getDSTSavings() == 0)
2607 || (tr1
.getTo()->getDSTSavings() == 0 && tr2
.getTo()->getDSTSavings() != 0)) {
2611 if (tr1
.getTo()->getRawOffset() != tr2
.getTo()->getRawOffset() ||
2612 tr1
.getTo()->getDSTSavings() != tr2
.getTo()->getDSTSavings()) {
2616 time
= tr1
.getTime() > tr2
.getTime() ? tr1
.getTime() : tr2
.getTime();
2621 // Test case for ticket#8943
2622 // RuleBasedTimeZone#getOffsets throws NPE
2624 TimeZoneRuleTest::TestT8943(void) {
2625 UErrorCode status
= U_ZERO_ERROR
;
2626 UnicodeString
id("Ekaterinburg Time");
2627 UnicodeString
stdName("Ekaterinburg Standard Time");
2628 UnicodeString
dstName("Ekaterinburg Daylight Time");
2630 InitialTimeZoneRule
*initialRule
= new InitialTimeZoneRule(stdName
, 18000000, 0);
2631 RuleBasedTimeZone
*rbtz
= new RuleBasedTimeZone(id
, initialRule
);
2633 DateTimeRule
*dtRule
= new DateTimeRule(UCAL_OCTOBER
, -1, UCAL_SUNDAY
, 10800000, DateTimeRule::WALL_TIME
);
2634 AnnualTimeZoneRule
*atzRule
= new AnnualTimeZoneRule(stdName
, 18000000, 0, dtRule
, 2000, 2010);
2635 rbtz
->addTransitionRule(atzRule
, status
);
2637 dtRule
= new DateTimeRule(UCAL_MARCH
, -1, UCAL_SUNDAY
, 7200000, DateTimeRule::WALL_TIME
);
2638 atzRule
= new AnnualTimeZoneRule(dstName
, 18000000, 3600000, dtRule
, 2000, 2010);
2639 rbtz
->addTransitionRule(atzRule
, status
);
2641 dtRule
= new DateTimeRule(UCAL_JANUARY
, 1, 0, DateTimeRule::WALL_TIME
);
2642 atzRule
= new AnnualTimeZoneRule(stdName
, 21600000, 0, dtRule
, 2011, AnnualTimeZoneRule::MAX_YEAR
);
2643 rbtz
->addTransitionRule(atzRule
, status
);
2645 dtRule
= new DateTimeRule(UCAL_JANUARY
, 1, 1, DateTimeRule::WALL_TIME
);
2646 atzRule
= new AnnualTimeZoneRule(dstName
, 21600000, 0, dtRule
, 2011, AnnualTimeZoneRule::MAX_YEAR
);
2647 rbtz
->addTransitionRule(atzRule
, status
);
2648 rbtz
->complete(status
);
2650 if (U_FAILURE(status
)) {
2651 errln("Failed to construct a RuleBasedTimeZone");
2654 rbtz
->getOffset(1293822000000.0 /* 2010-12-31 19:00:00 UTC */, FALSE
, raw
, dst
, status
);
2655 if (U_FAILURE(status
)) {
2656 errln("Error invoking getOffset");
2657 } else if (raw
!= 21600000 || dst
!= 0) {
2658 errln(UnicodeString("Fail: Wrong offsets: ") + raw
+ "/" + dst
+ " Expected: 21600000/0");
2665 #endif /* #if !UCONFIG_NO_FORMATTING */