Home | History | Annotate | Download | only in intltest
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /***********************************************************************
      4  * COPYRIGHT:
      5  * Copyright (c) 1997-2010, International Business Machines Corporation
      6  * and others. All Rights Reserved.
      7  ***********************************************************************/
      8 
      9 #include "unicode/utypes.h"
     10 
     11 #if !UCONFIG_NO_FORMATTING
     12 
     13 #include "tzbdtest.h"
     14 #include "unicode/timezone.h"
     15 #include "unicode/simpletz.h"
     16 #include "unicode/gregocal.h"
     17 #include "putilimp.h"
     18 
     19 void TimeZoneBoundaryTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
     20 {
     21     if (exec) logln("TestSuite TestTimeZoneBoundary");
     22     switch (index) {
     23         case 0:
     24             name = "TestBoundaries";
     25             if (exec) {
     26                 logln("TestBoundaries---"); logln("");
     27                 TestBoundaries();
     28             }
     29             break;
     30         case 1:
     31             name = "TestNewRules";
     32             if (exec) {
     33                 logln("TestNewRules---"); logln("");
     34                 TestNewRules();
     35             }
     36             break;
     37         case 2:
     38             name = "TestStepwise";
     39             if (exec) {
     40                 logln("TestStepwise---"); logln("");
     41                 TestStepwise();
     42             }
     43             break;
     44         default: name = ""; break;
     45     }
     46 }
     47 
     48 // *****************************************************************************
     49 // class TimeZoneBoundaryTest
     50 // *****************************************************************************
     51 
     52 TimeZoneBoundaryTest::TimeZoneBoundaryTest()
     53 :
     54 ONE_SECOND(1000),
     55 ONE_MINUTE(60 * ONE_SECOND),
     56 ONE_HOUR(60 * ONE_MINUTE),
     57 ONE_DAY(24 * ONE_HOUR),
     58 ONE_YEAR(uprv_floor(365.25 * ONE_DAY)),
     59 SIX_MONTHS(ONE_YEAR / 2)
     60 {
     61 }
     62 
     63 const int32_t TimeZoneBoundaryTest::MONTH_LENGTH[] = {
     64     31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
     65 };
     66 
     67 const UDate TimeZoneBoundaryTest::PST_1997_BEG = 860320800000.0;
     68 
     69 const UDate TimeZoneBoundaryTest::PST_1997_END = 877856400000.0;
     70 
     71 const UDate TimeZoneBoundaryTest::INTERVAL = 10;
     72 
     73 // -------------------------------------
     74 
     75 void
     76 TimeZoneBoundaryTest::findDaylightBoundaryUsingDate(UDate d, const char* startMode, UDate expectedBoundary)
     77 {
     78     UnicodeString str;
     79     if (dateToString(d, str).indexOf(startMode) == - 1) {
     80         logln(UnicodeString("Error: ") + startMode + " not present in " + str);
     81     }
     82     UDate min = d;
     83     UDate max = min + SIX_MONTHS;
     84     while ((max - min) > INTERVAL) {
     85         UDate mid = (min + max) / 2;
     86         UnicodeString* s = &dateToString(mid, str);
     87         if (s->indexOf(startMode) != - 1) {
     88             min = mid;
     89         }
     90         else {
     91             max = mid;
     92         }
     93     }
     94     logln("Date Before: " + showDate(min));
     95     logln("Date After:  " + showDate(max));
     96     UDate mindelta = expectedBoundary - min;
     97     UDate maxdelta = max - expectedBoundary;
     98     if (mindelta >= 0 &&
     99         mindelta <= INTERVAL &&
    100         maxdelta >= 0 &&
    101         maxdelta <= INTERVAL) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary);
    102     else dataerrln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary);
    103 }
    104 
    105 // -------------------------------------
    106 
    107 void
    108 TimeZoneBoundaryTest::findDaylightBoundaryUsingTimeZone(UDate d, UBool startsInDST, UDate expectedBoundary)
    109 {
    110     TimeZone *zone = TimeZone::createDefault();
    111     findDaylightBoundaryUsingTimeZone(d, startsInDST, expectedBoundary, zone);
    112     delete zone;
    113 }
    114 
    115 // -------------------------------------
    116 
    117 void
    118 TimeZoneBoundaryTest::findDaylightBoundaryUsingTimeZone(UDate d, UBool startsInDST, UDate expectedBoundary, TimeZone* tz)
    119 {
    120     UErrorCode status = U_ZERO_ERROR;
    121     UnicodeString str;
    122     UDate min = d;
    123     UDate max = min + SIX_MONTHS;
    124     if (tz->inDaylightTime(d, status) != startsInDST) {
    125         dataerrln("FAIL: " + tz->getID(str) + " inDaylightTime(" + dateToString(d) + ") != " + (startsInDST ? "true" : "false"));
    126         startsInDST = !startsInDST;
    127     }
    128     if (failure(status, "TimeZone::inDaylightTime", TRUE)) return;
    129     if (tz->inDaylightTime(max, status) == startsInDST) {
    130         dataerrln("FAIL: " + tz->getID(str) + " inDaylightTime(" + dateToString(max) + ") != " + (startsInDST ? "false" : "true"));
    131         return;
    132     }
    133     if (failure(status, "TimeZone::inDaylightTime")) return;
    134     while ((max - min) > INTERVAL) {
    135         UDate mid = (min + max) / 2;
    136         UBool isIn = tz->inDaylightTime(mid, status);
    137         if (failure(status, "TimeZone::inDaylightTime")) return;
    138         if (isIn == startsInDST) {
    139             min = mid;
    140         }
    141         else {
    142             max = mid;
    143         }
    144     }
    145     logln(tz->getID(str) + " Before: " + showDate(min));
    146     logln(tz->getID(str) + " After:  " + showDate(max));
    147     UDate mindelta = expectedBoundary - min;
    148     UDate maxdelta = max - expectedBoundary;
    149     if (mindelta >= 0 &&
    150         mindelta <= INTERVAL &&
    151         maxdelta >= 0 &&
    152         maxdelta <= INTERVAL) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary);
    153     else errln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary);
    154 }
    155 
    156 // -------------------------------------
    157 /*
    158 UnicodeString*
    159 TimeZoneBoundaryTest::showDate(int32_t l)
    160 {
    161     return showDate(new Date(l));
    162 }
    163 */
    164 // -------------------------------------
    165 
    166 UnicodeString
    167 TimeZoneBoundaryTest::showDate(UDate d)
    168 {
    169     int32_t y, m, day, h, min, sec;
    170     dateToFields(d, y, m, day, h, min, sec);
    171     return UnicodeString("") + y + "/" + showNN(m + 1) + "/" +
    172         showNN(day) + " " + showNN(h) + ":" + showNN(min) +
    173         " \"" + dateToString(d) + "\" = " + uprv_floor(d+0.5);
    174 }
    175 
    176 // -------------------------------------
    177 
    178 UnicodeString
    179 TimeZoneBoundaryTest::showNN(int32_t n)
    180 {
    181     UnicodeString nStr;
    182     if (n < 10) {
    183         nStr += UnicodeString("0", "");
    184     }
    185     return nStr + n;
    186 }
    187 
    188 // -------------------------------------
    189 
    190 void
    191 TimeZoneBoundaryTest::verifyDST(UDate d, TimeZone* time_zone, UBool expUseDaylightTime, UBool expInDaylightTime, UDate expZoneOffset, UDate expDSTOffset)
    192 {
    193     UnicodeString str;
    194     UErrorCode status = U_ZERO_ERROR;
    195     logln("-- Verifying time " + dateToString(d) + " in zone " + time_zone->getID(str));
    196     if (time_zone->inDaylightTime(d, status) == expInDaylightTime)
    197         logln(UnicodeString("PASS: inDaylightTime = ") + (time_zone->inDaylightTime(d, status)?"true":"false"));
    198     else
    199         dataerrln(UnicodeString("FAIL: inDaylightTime = ") + (time_zone->inDaylightTime(d, status)?"true":"false"));
    200     if (failure(status, "TimeZone::inDaylightTime", TRUE))
    201         return;
    202     if (time_zone->useDaylightTime() == expUseDaylightTime)
    203         logln(UnicodeString("PASS: useDaylightTime = ") + (time_zone->useDaylightTime()?"true":"false"));
    204     else
    205         dataerrln(UnicodeString("FAIL: useDaylightTime = ") + (time_zone->useDaylightTime()?"true":"false"));
    206     if (time_zone->getRawOffset() == expZoneOffset)
    207         logln(UnicodeString("PASS: getRawOffset() = ") + (expZoneOffset / ONE_HOUR));
    208     else
    209         dataerrln(UnicodeString("FAIL: getRawOffset() = ") + (time_zone->getRawOffset() / ONE_HOUR) + ";  expected " + (expZoneOffset / ONE_HOUR));
    210 
    211     GregorianCalendar *gc = new GregorianCalendar(time_zone->clone(), status);
    212     gc->setTime(d, status);
    213     if (failure(status, "GregorianCalendar::setTime")) return;
    214     int32_t offset = time_zone->getOffset((uint8_t)gc->get(UCAL_ERA, status),
    215         gc->get(UCAL_YEAR, status), gc->get(UCAL_MONTH, status),
    216         gc->get(UCAL_DATE, status), (uint8_t)gc->get(UCAL_DAY_OF_WEEK, status),
    217         ((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),
    218         status);
    219     if (failure(status, "GregorianCalendar::get")) return;
    220     if (offset == expDSTOffset) logln(UnicodeString("PASS: getOffset() = ") + (offset / ONE_HOUR));
    221     else dataerrln(UnicodeString("FAIL: getOffset() = ") + (offset / ONE_HOUR) + "; expected " + (expDSTOffset / ONE_HOUR));
    222     delete gc;
    223 }
    224 
    225 // -------------------------------------
    226 /**
    227     * Check that the given year/month/dom/hour maps to and from the
    228     * given epochHours.  This verifies the functioning of the
    229     * calendar and time zone in conjunction with one another,
    230     * including the calendar time->fields and fields->time and
    231     * the time zone getOffset method.
    232     *
    233     * @param epochHours hours after Jan 1 1970 0:00 GMT.
    234     */
    235 void TimeZoneBoundaryTest::verifyMapping(Calendar& cal, int year, int month, int dom, int hour,
    236                     double epochHours) {
    237     double H = 3600000.0;
    238     UErrorCode status = U_ZERO_ERROR;
    239     cal.clear();
    240     cal.set(year, month, dom, hour, 0, 0);
    241     UDate e = cal.getTime(status)/ H;
    242     UDate ed = (epochHours * H);
    243     if (e == epochHours) {
    244         logln(UnicodeString("Ok: ") + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +
    245                 e + " (" + ed + ")");
    246     } else {
    247         dataerrln(UnicodeString("FAIL: ") + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +
    248                 e + " (" + (e * H) + ")" +
    249                 ", expected " + epochHours + " (" + ed + ")");
    250     }
    251     cal.setTime(ed, status);
    252     if (cal.get(UCAL_YEAR, status) == year &&
    253         cal.get(UCAL_MONTH, status) == month &&
    254         cal.get(UCAL_DATE, status) == dom &&
    255         cal.get(UCAL_MILLISECONDS_IN_DAY, status) == hour * 3600000) {
    256         logln(UnicodeString("Ok: ") + epochHours + " (" + ed + ") => " +
    257                 cal.get(UCAL_YEAR, status) + "/" +
    258                 (cal.get(UCAL_MONTH, status)+1) + "/" +
    259                 cal.get(UCAL_DATE, status) + " " +
    260                 cal.get(UCAL_MILLISECOND, status)/H);
    261     } else {
    262         dataerrln(UnicodeString("FAIL: ") + epochHours + " (" + ed + ") => " +
    263                 cal.get(UCAL_YEAR, status) + "/" +
    264                 (cal.get(UCAL_MONTH, status)+1) + "/" +
    265                 cal.get(UCAL_DATE, status) + " " +
    266                 cal.get(UCAL_MILLISECOND, status)/H +
    267                 ", expected " + year + "/" + (month+1) + "/" + dom +
    268                 " " + hour);
    269     }
    270 }
    271 
    272 /**
    273  * Test the behavior of SimpleTimeZone at the transition into and out of DST.
    274  * Use a binary search to find boundaries.
    275  */
    276 void
    277 TimeZoneBoundaryTest::TestBoundaries()
    278 {
    279     UErrorCode status = U_ZERO_ERROR;
    280     TimeZone* pst = TimeZone::createTimeZone("PST");
    281     Calendar* tempcal = Calendar::createInstance(pst, status);
    282     if(U_SUCCESS(status)){
    283         verifyMapping(*tempcal, 1997, Calendar::APRIL, 3,  0, 238904.0);
    284         verifyMapping(*tempcal, 1997, Calendar::APRIL, 4,  0, 238928.0);
    285         verifyMapping(*tempcal, 1997, Calendar::APRIL, 5,  0, 238952.0);
    286         verifyMapping(*tempcal, 1997, Calendar::APRIL, 5, 23, 238975.0);
    287         verifyMapping(*tempcal, 1997, Calendar::APRIL, 6,  0, 238976.0);
    288         verifyMapping(*tempcal, 1997, Calendar::APRIL, 6,  1, 238977.0);
    289         verifyMapping(*tempcal, 1997, Calendar::APRIL, 6,  3, 238978.0);
    290     }else{
    291         dataerrln("Could not create calendar. Error: %s", u_errorName(status));
    292     }
    293     TimeZone* utc = TimeZone::createTimeZone("UTC");
    294     Calendar* utccal =  Calendar::createInstance(utc, status);
    295     if(U_SUCCESS(status)){
    296         verifyMapping(*utccal, 1997, Calendar::APRIL, 6, 0, 238968.0);
    297     }else{
    298         dataerrln("Could not create calendar. Error: %s", u_errorName(status));
    299     }
    300     TimeZone* save = TimeZone::createDefault();
    301     TimeZone::setDefault(*pst);
    302 
    303     if (tempcal != NULL) {
    304         // DST changeover for PST is 4/6/1997 at 2 hours past midnight
    305         // at 238978.0 epoch hours.
    306         tempcal->clear();
    307         tempcal->set(1997, Calendar::APRIL, 6);
    308         UDate d = tempcal->getTime(status);
    309 
    310         // i is minutes past midnight standard time
    311         for (int i=-120; i<=180; i+=60)
    312         {
    313             UBool inDST = (i >= 120);
    314             tempcal->setTime(d + i*60*1000, status);
    315             verifyDST(tempcal->getTime(status),pst, TRUE, inDST, -8*ONE_HOUR,inDST ? -7*ONE_HOUR : -8*ONE_HOUR);
    316         }
    317     }
    318     TimeZone::setDefault(*save);
    319     delete save;
    320     delete utccal;
    321     delete tempcal;
    322 
    323 #if 1
    324     {
    325         logln("--- Test a ---");
    326         UDate d = date(97, UCAL_APRIL, 6);
    327         TimeZone *z = TimeZone::createTimeZone("PST");
    328         for (int32_t i = 60; i <= 180; i += 15) {
    329             UBool inDST = (i >= 120);
    330             UDate e = d + i * 60 * 1000;
    331             verifyDST(e, z, TRUE, inDST, - 8 * ONE_HOUR, inDST ? - 7 * ONE_HOUR: - 8 * ONE_HOUR);
    332         }
    333         delete z;
    334     }
    335 #endif
    336 #if 1
    337     {
    338         logln("--- Test b ---");
    339         TimeZone *tz;
    340         TimeZone::setDefault(*(tz = TimeZone::createTimeZone("PST")));
    341         delete tz;
    342         logln("========================================");
    343         findDaylightBoundaryUsingDate(date(97, 0, 1), "PST", PST_1997_BEG);
    344         logln("========================================");
    345         findDaylightBoundaryUsingDate(date(97, 6, 1), "PDT", PST_1997_END);
    346     }
    347 #endif
    348 #if 1
    349     {
    350         logln("--- Test c ---");
    351         logln("========================================");
    352         TimeZone* z = TimeZone::createTimeZone("Australia/Adelaide");
    353         findDaylightBoundaryUsingTimeZone(date(97, 0, 1), TRUE, 859653000000.0, z);
    354         logln("========================================");
    355         findDaylightBoundaryUsingTimeZone(date(97, 6, 1), FALSE, 877797000000.0, z);
    356         delete z;
    357     }
    358 #endif
    359 #if 1
    360     {
    361         logln("--- Test d ---");
    362         logln("========================================");
    363         findDaylightBoundaryUsingTimeZone(date(97, 0, 1), FALSE, PST_1997_BEG);
    364         logln("========================================");
    365         findDaylightBoundaryUsingTimeZone(date(97, 6, 1), TRUE, PST_1997_END);
    366     }
    367 #endif
    368 #if 0
    369     {
    370         logln("--- Test e ---");
    371         TimeZone *z = TimeZone::createDefault();
    372         logln(UnicodeString("") + z->getOffset(1, 97, 3, 4, 6, 0) + " " + date(97, 3, 4));
    373         logln(UnicodeString("") + z->getOffset(1, 97, 3, 5, 7, 0) + " " + date(97, 3, 5));
    374         logln(UnicodeString("") + z->getOffset(1, 97, 3, 6, 1, 0) + " " + date(97, 3, 6));
    375         logln(UnicodeString("") + z->getOffset(1, 97, 3, 7, 2, 0) + " " + date(97, 3, 7));
    376         delete z;
    377     }
    378 #endif
    379 }
    380 
    381 // -------------------------------------
    382 
    383 void
    384 TimeZoneBoundaryTest::testUsingBinarySearch(SimpleTimeZone* tz, UDate d, UDate expectedBoundary)
    385 {
    386     UErrorCode status = U_ZERO_ERROR;
    387     UDate min = d;
    388     UDate max = min + SIX_MONTHS;
    389     UBool startsInDST = tz->inDaylightTime(d, status);
    390     if (failure(status, "SimpleTimeZone::inDaylightTime", TRUE)) return;
    391     if (tz->inDaylightTime(max, status) == startsInDST) {
    392         errln("Error: inDaylightTime(" + dateToString(max) + ") != " + ((!startsInDST)?"true":"false"));
    393     }
    394     if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
    395     while ((max - min) > INTERVAL) {
    396         UDate mid = (min + max) / 2;
    397         if (tz->inDaylightTime(mid, status) == startsInDST) {
    398             min = mid;
    399         }
    400         else {
    401             max = mid;
    402         }
    403         if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
    404     }
    405     logln("Binary Search Before: " + showDate(min));
    406     logln("Binary Search After:  " + showDate(max));
    407     UDate mindelta = expectedBoundary - min;
    408     UDate maxdelta = max - expectedBoundary;
    409     if (mindelta >= 0 &&
    410         mindelta <= INTERVAL &&
    411         maxdelta >= 0 &&
    412         maxdelta <= INTERVAL) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary);
    413     else errln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary);
    414 }
    415 
    416 // -------------------------------------
    417 
    418 /**
    419  * Test the handling of the "new" rules; that is, rules other than nth Day of week.
    420  */
    421 void
    422 TimeZoneBoundaryTest::TestNewRules()
    423 {
    424 #if 1
    425     {
    426         UErrorCode status = U_ZERO_ERROR;
    427         SimpleTimeZone *tz;
    428         logln("-----------------------------------------------------------------");
    429         logln("Aug 2ndTues .. Mar 15");
    430         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);
    431         logln("========================================");
    432         testUsingBinarySearch(tz, date(97, 0, 1), 858416400000.0);
    433         logln("========================================");
    434         testUsingBinarySearch(tz, date(97, 6, 1), 871380000000.0);
    435         delete tz;
    436         logln("-----------------------------------------------------------------");
    437         logln("Apr Wed>=14 .. Sep Sun<=20");
    438         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);
    439         logln("========================================");
    440         testUsingBinarySearch(tz, date(97, 0, 1), 861184800000.0);
    441         logln("========================================");
    442         testUsingBinarySearch(tz, date(97, 6, 1), 874227600000.0);
    443         delete tz;
    444     }
    445 #endif
    446 }
    447 
    448 // -------------------------------------
    449 
    450 void
    451 TimeZoneBoundaryTest::findBoundariesStepwise(int32_t year, UDate interval, TimeZone* z, int32_t expectedChanges)
    452 {
    453     UErrorCode status = U_ZERO_ERROR;
    454     UnicodeString str;
    455     UDate d = date(year - 1900, UCAL_JANUARY, 1);
    456     UDate time = d;
    457     UDate limit = time + ONE_YEAR + ONE_DAY;
    458     UBool lastState = z->inDaylightTime(d, status);
    459     if (failure(status, "TimeZone::inDaylightTime", TRUE)) return;
    460     int32_t changes = 0;
    461     logln(UnicodeString("-- Zone ") + z->getID(str) + " starts in " + year + " with DST = " + (lastState?"true":"false"));
    462     logln(UnicodeString("useDaylightTime = ") + (z->useDaylightTime()?"true":"false"));
    463     while (time < limit) {
    464         d = time;
    465         UBool state = z->inDaylightTime(d, status);
    466         if (failure(status, "TimeZone::inDaylightTime")) return;
    467         if (state != lastState) {
    468             logln(UnicodeString(state ? "Entry ": "Exit ") + "at " + d);
    469             lastState = state;++changes;
    470         }
    471         time += interval;
    472     }
    473     if (changes == 0) {
    474         if (!lastState &&
    475             !z->useDaylightTime()) logln("No DST");
    476         else errln("FAIL: DST all year, or no DST with true useDaylightTime");
    477     }
    478     else if (changes != 2) {
    479         errln(UnicodeString("FAIL: ") + changes + " changes seen; should see 0 or 2");
    480     }
    481     else if (!z->useDaylightTime()) {
    482         errln("FAIL: useDaylightTime false but 2 changes seen");
    483     }
    484     if (changes != expectedChanges) {
    485         dataerrln(UnicodeString("FAIL: ") + changes + " changes seen; expected " + expectedChanges);
    486     }
    487 }
    488 
    489 // -------------------------------------
    490 
    491 /**
    492  * This test is problematic. It makes assumptions about the behavior
    493  * of specific zones. Since ICU's zone table is based on the Olson
    494  * zones (the UNIX zones), and those change from time to time, this
    495  * test can fail after a zone table update. If that happens, the
    496  * selected zones need to be updated to have the behavior
    497  * expected. That is, they should have DST, not have DST, and have DST
    498  * -- other than that this test isn't picky. 12/3/99 aliu
    499  *
    500  * Test the behavior of SimpleTimeZone at the transition into and out of DST.
    501  * Use a stepwise march to find boundaries.
    502  */
    503 void
    504 TimeZoneBoundaryTest::TestStepwise()
    505 {
    506     TimeZone *zone =  TimeZone::createTimeZone("America/New_York");
    507     findBoundariesStepwise(1997, ONE_DAY, zone, 2);
    508     delete zone;
    509     zone = TimeZone::createTimeZone("UTC"); // updated 12/3/99 aliu
    510     findBoundariesStepwise(1997, ONE_DAY, zone, 0);
    511     delete zone;
    512     zone = TimeZone::createTimeZone("Australia/Adelaide");
    513     findBoundariesStepwise(1997, ONE_DAY, zone, 2);
    514     delete zone;
    515 }
    516 
    517 #endif /* #if !UCONFIG_NO_FORMATTING */
    518