]>
git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/tzbdtest.cpp
1 /***********************************************************************
3 * Copyright (c) 1997-2004, International Business Machines Corporation
4 * and others. All Rights Reserved.
5 ***********************************************************************/
7 #include "unicode/utypes.h"
9 #if !UCONFIG_NO_FORMATTING
12 #include "unicode/timezone.h"
13 #include "unicode/simpletz.h"
14 #include "unicode/gregocal.h"
17 void TimeZoneBoundaryTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/ )
19 if (exec
) logln("TestSuite TestTimeZoneBoundary");
22 name
= "TestBoundaries";
24 logln("TestBoundaries---"); logln("");
29 name
= "TestNewRules";
31 logln("TestNewRules---"); logln("");
36 name
= "TestStepwise";
38 logln("TestStepwise---"); logln("");
42 default: name
= ""; break;
46 // *****************************************************************************
47 // class TimeZoneBoundaryTest
48 // *****************************************************************************
50 TimeZoneBoundaryTest::TimeZoneBoundaryTest()
53 ONE_MINUTE(60 * ONE_SECOND
),
54 ONE_HOUR(60 * ONE_MINUTE
),
55 ONE_DAY(24 * ONE_HOUR
),
56 ONE_YEAR(uprv_floor(365.25 * ONE_DAY
)),
57 SIX_MONTHS(ONE_YEAR
/ 2)
61 const int32_t TimeZoneBoundaryTest::MONTH_LENGTH
[] = {
62 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
65 const UDate
TimeZoneBoundaryTest::PST_1997_BEG
= 860320800000.0;
67 const UDate
TimeZoneBoundaryTest::PST_1997_END
= 877856400000.0;
69 const UDate
TimeZoneBoundaryTest::INTERVAL
= 10;
71 // -------------------------------------
74 TimeZoneBoundaryTest::findDaylightBoundaryUsingDate(UDate d
, const char* startMode
, UDate expectedBoundary
)
77 if (dateToString(d
, str
).indexOf(startMode
) == - 1) {
78 logln(UnicodeString("Error: ") + startMode
+ " not present in " + str
);
81 UDate max
= min
+ SIX_MONTHS
;
82 while ((max
- min
) > INTERVAL
) {
83 UDate mid
= (min
+ max
) / 2;
84 UnicodeString
* s
= &dateToString(mid
, str
);
85 if (s
->indexOf(startMode
) != - 1) {
92 logln("Date Before: " + showDate(min
));
93 logln("Date After: " + showDate(max
));
94 UDate mindelta
= expectedBoundary
- min
;
95 UDate maxdelta
= max
- expectedBoundary
;
97 mindelta
<= INTERVAL
&&
99 maxdelta
<= INTERVAL
) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary
);
100 else errln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary
);
103 // -------------------------------------
106 TimeZoneBoundaryTest::findDaylightBoundaryUsingTimeZone(UDate d
, UBool startsInDST
, UDate expectedBoundary
)
108 TimeZone
*zone
= TimeZone::createDefault();
109 findDaylightBoundaryUsingTimeZone(d
, startsInDST
, expectedBoundary
, zone
);
113 // -------------------------------------
116 TimeZoneBoundaryTest::findDaylightBoundaryUsingTimeZone(UDate d
, UBool startsInDST
, UDate expectedBoundary
, TimeZone
* tz
)
118 UErrorCode status
= U_ZERO_ERROR
;
121 UDate max
= min
+ SIX_MONTHS
;
122 if (tz
->inDaylightTime(d
, status
) != startsInDST
) {
123 errln("FAIL: " + tz
->getID(str
) + " inDaylightTime(" + dateToString(d
) + ") != " + (startsInDST
? "true" : "false"));
124 startsInDST
= !startsInDST
;
126 if (failure(status
, "TimeZone::inDaylightTime")) return;
127 if (tz
->inDaylightTime(max
, status
) == startsInDST
) {
128 errln("FAIL: " + tz
->getID(str
) + " inDaylightTime(" + dateToString(max
) + ") != " + (startsInDST
? "false" : "true"));
131 if (failure(status
, "TimeZone::inDaylightTime")) return;
132 while ((max
- min
) > INTERVAL
) {
133 UDate mid
= (min
+ max
) / 2;
134 UBool isIn
= tz
->inDaylightTime(mid
, status
);
135 if (failure(status
, "TimeZone::inDaylightTime")) return;
136 if (isIn
== startsInDST
) {
143 logln(tz
->getID(str
) + " Before: " + showDate(min
));
144 logln(tz
->getID(str
) + " After: " + showDate(max
));
145 UDate mindelta
= expectedBoundary
- min
;
146 UDate maxdelta
= max
- expectedBoundary
;
148 mindelta
<= INTERVAL
&&
150 maxdelta
<= INTERVAL
) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary
);
151 else errln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary
);
154 // -------------------------------------
157 TimeZoneBoundaryTest::showDate(int32_t l)
159 return showDate(new Date(l));
162 // -------------------------------------
165 TimeZoneBoundaryTest::showDate(UDate d
)
167 int32_t y
, m
, day
, h
, min
, sec
;
168 dateToFields(d
, y
, m
, day
, h
, min
, sec
);
169 return UnicodeString("") + y
+ "/" + showNN(m
+ 1) + "/" +
170 showNN(day
) + " " + showNN(h
) + ":" + showNN(min
) +
171 " \"" + dateToString(d
) + "\" = " + uprv_floor(d
+0.5);
174 // -------------------------------------
177 TimeZoneBoundaryTest::showNN(int32_t n
)
181 nStr
+= UnicodeString("0", "");
186 // -------------------------------------
189 TimeZoneBoundaryTest::verifyDST(UDate d
, TimeZone
* time_zone
, UBool expUseDaylightTime
, UBool expInDaylightTime
, UDate expZoneOffset
, UDate expDSTOffset
)
192 UErrorCode status
= U_ZERO_ERROR
;
193 logln("-- Verifying time " + dateToString(d
) + " in zone " + time_zone
->getID(str
));
194 if (time_zone
->inDaylightTime(d
, status
) == expInDaylightTime
)
195 logln(UnicodeString("PASS: inDaylightTime = ") + (time_zone
->inDaylightTime(d
, status
)?"true":"false"));
196 else errln(UnicodeString("FAIL: inDaylightTime = ") + (time_zone
->inDaylightTime(d
, status
)?"true":"false"));
197 if (failure(status
, "TimeZone::inDaylightTime")) return;
198 if (time_zone
->useDaylightTime() == expUseDaylightTime
)
199 logln(UnicodeString("PASS: useDaylightTime = ") + (time_zone
->useDaylightTime()?"true":"false"));
200 else errln(UnicodeString("FAIL: useDaylightTime = ") + (time_zone
->useDaylightTime()?"true":"false"));
201 if (time_zone
->getRawOffset() == expZoneOffset
) logln(UnicodeString("PASS: getRawOffset() = ") + (expZoneOffset
/ ONE_HOUR
));
202 else errln(UnicodeString("FAIL: getRawOffset() = ") + (time_zone
->getRawOffset() / ONE_HOUR
) + "; expected " + (expZoneOffset
/ ONE_HOUR
));
203 GregorianCalendar
*gc
= new GregorianCalendar(time_zone
->clone(), status
);
204 gc
->setTime(d
, status
);
205 if (failure(status
, "GregorianCalendar::setTime")) return;
206 int32_t offset
= time_zone
->getOffset((uint8_t)gc
->get(UCAL_ERA
, status
),
207 gc
->get(UCAL_YEAR
, status
), gc
->get(UCAL_MONTH
, status
),
208 gc
->get(UCAL_DATE
, status
), (uint8_t)gc
->get(UCAL_DAY_OF_WEEK
, status
),
209 ((gc
->get(UCAL_HOUR_OF_DAY
, status
) * 60 + gc
->get(UCAL_MINUTE
, status
)) * 60 + gc
->get(UCAL_SECOND
, status
)) * 1000 + gc
->get(UCAL_MILLISECOND
, status
),
211 if (failure(status
, "GregorianCalendar::get")) return;
212 if (offset
== expDSTOffset
) logln(UnicodeString("PASS: getOffset() = ") + (offset
/ ONE_HOUR
));
213 else errln(UnicodeString("FAIL: getOffset() = ") + (offset
/ ONE_HOUR
) + "; expected " + (expDSTOffset
/ ONE_HOUR
));
217 // -------------------------------------
220 * Test the behavior of SimpleTimeZone at the transition into and out of DST.
221 * Use a binary search to find boundaries.
224 TimeZoneBoundaryTest::TestBoundaries()
228 logln("--- Test a ---");
229 UDate d
= date(97, UCAL_APRIL
, 6);
230 TimeZone
*z
= TimeZone::createTimeZone("PST");
231 for (int32_t i
= 60; i
<= 180; i
+= 15) {
232 UBool inDST
= (i
>= 120);
233 UDate e
= d
+ i
* 60 * 1000;
234 verifyDST(e
, z
, TRUE
, inDST
, - 8 * ONE_HOUR
, inDST
? - 7 * ONE_HOUR
: - 8 * ONE_HOUR
);
241 logln("--- Test b ---");
243 TimeZone::setDefault(*(tz
= TimeZone::createTimeZone("PST")));
245 logln("========================================");
246 findDaylightBoundaryUsingDate(date(97, 0, 1), "PST", PST_1997_BEG
);
247 logln("========================================");
248 findDaylightBoundaryUsingDate(date(97, 6, 1), "PDT", PST_1997_END
);
253 logln("--- Test c ---");
254 logln("========================================");
255 TimeZone
* z
= TimeZone::createTimeZone("Australia/Adelaide");
256 findDaylightBoundaryUsingTimeZone(date(97, 0, 1), TRUE
, 859653000000.0, z
);
257 logln("========================================");
258 findDaylightBoundaryUsingTimeZone(date(97, 6, 1), FALSE
, 877797000000.0, z
);
264 logln("--- Test d ---");
265 logln("========================================");
266 findDaylightBoundaryUsingTimeZone(date(97, 0, 1), FALSE
, PST_1997_BEG
);
267 logln("========================================");
268 findDaylightBoundaryUsingTimeZone(date(97, 6, 1), TRUE
, PST_1997_END
);
273 logln("--- Test e ---");
274 TimeZone
*z
= TimeZone::createDefault();
275 logln(UnicodeString("") + z
->getOffset(1, 97, 3, 4, 6, 0) + " " + date(97, 3, 4));
276 logln(UnicodeString("") + z
->getOffset(1, 97, 3, 5, 7, 0) + " " + date(97, 3, 5));
277 logln(UnicodeString("") + z
->getOffset(1, 97, 3, 6, 1, 0) + " " + date(97, 3, 6));
278 logln(UnicodeString("") + z
->getOffset(1, 97, 3, 7, 2, 0) + " " + date(97, 3, 7));
284 // -------------------------------------
287 TimeZoneBoundaryTest::testUsingBinarySearch(SimpleTimeZone
* tz
, UDate d
, UDate expectedBoundary
)
289 UErrorCode status
= U_ZERO_ERROR
;
291 UDate max
= min
+ SIX_MONTHS
;
292 UBool startsInDST
= tz
->inDaylightTime(d
, status
);
293 if (failure(status
, "SimpleTimeZone::inDaylightTime")) return;
294 if (tz
->inDaylightTime(max
, status
) == startsInDST
) {
295 logln("Error: inDaylightTime(" + dateToString(max
) + ") != " + ((!startsInDST
)?"true":"false"));
297 if (failure(status
, "SimpleTimeZone::inDaylightTime")) return;
298 while ((max
- min
) > INTERVAL
) {
299 UDate mid
= (min
+ max
) / 2;
300 if (tz
->inDaylightTime(mid
, status
) == startsInDST
) {
306 if (failure(status
, "SimpleTimeZone::inDaylightTime")) return;
308 logln("Binary Search Before: " + showDate(min
));
309 logln("Binary Search After: " + showDate(max
));
310 UDate mindelta
= expectedBoundary
- min
;
311 UDate maxdelta
= max
- expectedBoundary
;
313 mindelta
<= INTERVAL
&&
315 maxdelta
<= INTERVAL
) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary
);
316 else errln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary
);
319 // -------------------------------------
322 * Test the handling of the "new" rules; that is, rules other than nth Day of week.
325 TimeZoneBoundaryTest::TestNewRules()
329 UErrorCode status
= U_ZERO_ERROR
;
331 logln("-----------------------------------------------------------------");
332 logln("Aug 2ndTues .. Mar 15");
333 tz
= new SimpleTimeZone(- 8 * (int32_t)ONE_HOUR
, "Test_1", UCAL_AUGUST
, 2, UCAL_TUESDAY
, 2 * (int32_t)ONE_HOUR
, UCAL_MARCH
, 15, 0, 2 * (int32_t)ONE_HOUR
, status
);
334 logln("========================================");
335 testUsingBinarySearch(tz
, date(97, 0, 1), 858416400000.0);
336 logln("========================================");
337 testUsingBinarySearch(tz
, date(97, 6, 1), 871380000000.0);
339 logln("-----------------------------------------------------------------");
340 logln("Apr Wed>=14 .. Sep Sun<=20");
341 tz
= new SimpleTimeZone(- 8 * (int32_t)ONE_HOUR
, "Test_2", UCAL_APRIL
, 14, - UCAL_WEDNESDAY
, 2 *(int32_t)ONE_HOUR
, UCAL_SEPTEMBER
, - 20, - UCAL_SUNDAY
, 2 * (int32_t)ONE_HOUR
, status
);
342 logln("========================================");
343 testUsingBinarySearch(tz
, date(97, 0, 1), 861184800000.0);
344 logln("========================================");
345 testUsingBinarySearch(tz
, date(97, 6, 1), 874227600000.0);
351 // -------------------------------------
354 TimeZoneBoundaryTest::findBoundariesStepwise(int32_t year
, UDate interval
, TimeZone
* z
, int32_t expectedChanges
)
356 UErrorCode status
= U_ZERO_ERROR
;
358 UDate d
= date(year
- 1900, UCAL_JANUARY
, 1);
360 UDate limit
= time
+ ONE_YEAR
+ ONE_DAY
;
361 UBool lastState
= z
->inDaylightTime(d
, status
);
362 if (failure(status
, "TimeZone::inDaylightTime")) return;
364 logln(UnicodeString("-- Zone ") + z
->getID(str
) + " starts in " + year
+ " with DST = " + (lastState
?"true":"false"));
365 logln(UnicodeString("useDaylightTime = ") + (z
->useDaylightTime()?"true":"false"));
366 while (time
< limit
) {
368 UBool state
= z
->inDaylightTime(d
, status
);
369 if (failure(status
, "TimeZone::inDaylightTime")) return;
370 if (state
!= lastState
) {
371 logln(UnicodeString(state
? "Entry ": "Exit ") + "at " + d
);
372 lastState
= state
;++changes
;
378 !z
->useDaylightTime()) logln("No DST");
379 else errln("FAIL: DST all year, or no DST with true useDaylightTime");
381 else if (changes
!= 2) {
382 errln(UnicodeString("FAIL: ") + changes
+ " changes seen; should see 0 or 2");
384 else if (!z
->useDaylightTime()) {
385 errln("FAIL: useDaylightTime false but 2 changes seen");
387 if (changes
!= expectedChanges
) {
388 errln(UnicodeString("FAIL: ") + changes
+ " changes seen; expected " + expectedChanges
);
392 // -------------------------------------
395 * This test is problematic. It makes assumptions about the behavior
396 * of specific zones. Since ICU's zone table is based on the Olson
397 * zones (the UNIX zones), and those change from time to time, this
398 * test can fail after a zone table update. If that happens, the
399 * selected zones need to be updated to have the behavior
400 * expected. That is, they should have DST, not have DST, and have DST
401 * -- other than that this test isn't picky. 12/3/99 aliu
403 * Test the behavior of SimpleTimeZone at the transition into and out of DST.
404 * Use a stepwise march to find boundaries.
407 TimeZoneBoundaryTest::TestStepwise()
409 TimeZone
*zone
= TimeZone::createTimeZone("America/New_York");
410 findBoundariesStepwise(1997, ONE_DAY
, zone
, 2);
412 zone
= TimeZone::createTimeZone("UTC"); // updated 12/3/99 aliu
413 findBoundariesStepwise(1997, ONE_DAY
, zone
, 0);
415 zone
= TimeZone::createTimeZone("Australia/Adelaide");
416 findBoundariesStepwise(1997, ONE_DAY
, zone
, 2);
420 #endif /* #if !UCONFIG_NO_FORMATTING */