home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / test / intltest / tzbdtest.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-07  |  15.0 KB  |  398 lines

  1.  
  2. /*
  3. ********************************************************************
  4. * COPYRIGHT: 
  5. * (C) Copyright Taligent, Inc., 1997
  6. * (C) Copyright International Business Machines Corporation, 1997 - 1998
  7. * Licensed Material - Program-Property of IBM - All Rights Reserved. 
  8. * US Government Users Restricted Rights - Use, duplication, or disclosure 
  9. * restricted by GSA ADP Schedule Contract with IBM Corp. 
  10. *
  11. ********************************************************************
  12. */
  13.  
  14. #include "tzbdtest.h"
  15. #include <math.h>
  16. #include "timezone.h"
  17. #include "simpletz.h"
  18. #include "gregocal.h"
  19.  
  20. void TimeZoneBoundaryTest::runIndexedTest( int32_t index, bool_t exec, char* &name, char* par )
  21. {
  22.     if (exec) logln("TestSuite TestTimeZoneBoundary");
  23.     switch (index) {
  24.         case 0:
  25.             name = "TestBoundaries";
  26.             if (exec) {
  27.                 logln("TestBoundaries---"); logln("");
  28.                 TestBoundaries();
  29.             }
  30.             break;
  31.         case 1:
  32.             name = "TestNewRules";
  33.             if (exec) {
  34.                 logln("TestNewRules---"); logln("");
  35.                 TestNewRules();
  36.             }
  37.             break;
  38.         case 2:
  39.             name = "TestStepwise";
  40.             if (exec) {
  41.                 logln("TestStepwise---"); logln("");
  42.                 TestStepwise();
  43.             }
  44.             break;
  45.         default: name = ""; break;
  46.     }
  47. }
  48.  
  49. // *****************************************************************************
  50. // class TimeZoneBoundaryTest
  51. // *****************************************************************************
  52.  
  53. UDate TimeZoneBoundaryTest::ONE_SECOND = 1000;
  54.  
  55. UDate TimeZoneBoundaryTest::ONE_MINUTE = 60 * ONE_SECOND;
  56.  
  57. UDate TimeZoneBoundaryTest::ONE_HOUR = 60 * ONE_MINUTE;
  58.  
  59. UDate TimeZoneBoundaryTest::ONE_DAY = 24 * ONE_HOUR;
  60.  
  61. UDate TimeZoneBoundaryTest::ONE_YEAR = icu_floor(365.25 * ONE_DAY);
  62.  
  63. UDate TimeZoneBoundaryTest::SIX_MONTHS = ONE_YEAR / 2;
  64.  
  65. int32_t TimeZoneBoundaryTest::MONTH_LENGTH[] = {
  66.     31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  67. };
  68.  
  69. UDate TimeZoneBoundaryTest::PST_1997_BEG = 860320800000.0;
  70.  
  71. UDate TimeZoneBoundaryTest::PST_1997_END = 877856400000.0;
  72.  
  73. UDate TimeZoneBoundaryTest::INTERVAL = 10;
  74.  
  75. // -------------------------------------
  76.  
  77. void
  78. TimeZoneBoundaryTest::findDaylightBoundaryUsingDate(UDate d, const char* startMode, UDate expectedBoundary)
  79. {
  80.     UnicodeString str;
  81.     if (dateToString(d, str).indexOf(startMode) == - 1) {
  82.         logln(UnicodeString("Error: ") + startMode + " not present in " + str);
  83.     }
  84.     UDate min = d;
  85.     UDate max = min + SIX_MONTHS;
  86.     while ((max - min) > INTERVAL) {
  87.         UDate mid = (min + max) / 2;
  88.         UnicodeString* s = &dateToString(mid, str);
  89.         if (s->indexOf(startMode) != - 1) {
  90.             min = mid;
  91.         }
  92.         else {
  93.             max = mid;
  94.         }
  95.     }
  96.     logln("Date Before: " + showDate(min));
  97.     logln("Date After:  " + showDate(max));
  98.     UDate mindelta = expectedBoundary - min;
  99.     UDate maxdelta = max - expectedBoundary;
  100.     if (mindelta >= 0 &&
  101.         mindelta <= INTERVAL &&
  102.         mindelta >= 0 &&
  103.         mindelta <= INTERVAL) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary);
  104.     else errln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary);
  105. }
  106.  
  107. // -------------------------------------
  108.  
  109. void
  110. TimeZoneBoundaryTest::findDaylightBoundaryUsingTimeZone(UDate d, bool_t startsInDST, UDate expectedBoundary)
  111. {
  112.     TimeZone *zone = TimeZone::createDefault();
  113.     findDaylightBoundaryUsingTimeZone(d, startsInDST, expectedBoundary, zone);
  114.     delete zone;
  115. }
  116.  
  117. // -------------------------------------
  118.  
  119. void
  120. TimeZoneBoundaryTest::findDaylightBoundaryUsingTimeZone(UDate d, bool_t startsInDST, UDate expectedBoundary, TimeZone* tz)
  121. {
  122.     UErrorCode status = U_ZERO_ERROR;
  123.     UnicodeString str;
  124.     UDate min = d;
  125.     UDate max = min + SIX_MONTHS;
  126.     if (tz->inDaylightTime(d, status) != startsInDST) {
  127.         errln("FAIL: " + tz->getID(str) + " inDaylightTime(" + dateToString(d) + ") != " + (startsInDST ? "true" : "false"));
  128.         startsInDST = !startsInDST;
  129.     }
  130.     if (failure(status, "TimeZone::inDaylightTime")) return;
  131.     if (tz->inDaylightTime(max, status) == startsInDST) {
  132.         errln("FAIL: " + tz->getID(str) + " inDaylightTime(" + dateToString(max) + ") != " + (startsInDST ? "false" : "true"));
  133.         return;
  134.     }
  135.     if (failure(status, "TimeZone::inDaylightTime")) return;
  136.     while ((max - min) > INTERVAL) {
  137.         UDate mid = (min + max) / 2;
  138.         bool_t isIn = tz->inDaylightTime(mid, status);
  139.         if (failure(status, "TimeZone::inDaylightTime")) return;
  140.         if (isIn == startsInDST) {
  141.             min = mid;
  142.         }
  143.         else {
  144.             max = mid;
  145.         }
  146.     }
  147.     logln(tz->getID(str) + " Before: " + showDate(min));
  148.     logln(tz->getID(str) + " After:  " + showDate(max));
  149.     UDate mindelta = expectedBoundary - min;
  150.     UDate maxdelta = max - expectedBoundary;
  151.     if (mindelta >= 0 &&
  152.         mindelta <= INTERVAL &&
  153.         mindelta >= 0 &&
  154.         mindelta <= INTERVAL) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary);
  155.     else errln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary);
  156. }
  157.  
  158. // -------------------------------------
  159. /*
  160. UnicodeString*
  161. TimeZoneBoundaryTest::showDate(int32_t l)
  162. {
  163.     return showDate(new Date(l));
  164. }
  165. */
  166. // -------------------------------------
  167.  
  168. UnicodeString
  169. TimeZoneBoundaryTest::showDate(UDate d)
  170. {
  171.     int32_t y, m, day, h, min, sec;
  172.     dateToFields(d, y, m, day, h, min, sec);
  173.     return UnicodeString("") + y + "/" + showNN(m + 1) + "/" +
  174.         showNN(day) + " " + showNN(h) + ":" + showNN(min) +
  175.         " \"" + dateToString(d) + "\" = " + icu_floor(d+0.5);
  176. }
  177.  
  178. // -------------------------------------
  179.  
  180. UnicodeString
  181. TimeZoneBoundaryTest::showNN(int32_t n)
  182. {
  183.     return ((n < 10) ? UnicodeString("0"): UnicodeString("")) + n;
  184. }
  185.  
  186. // -------------------------------------
  187.  
  188. void
  189. TimeZoneBoundaryTest::verifyDST(UDate d, TimeZone* time_zone, bool_t expUseDaylightTime, bool_t expInDaylightTime, UDate expZoneOffset, UDate expDSTOffset)
  190. {
  191.     UnicodeString str;
  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(gc->ERA, status),
  207.         gc->get(gc->YEAR, status), gc->get(gc->MONTH, status),
  208.         gc->get(gc->DAY_OF_MONTH, status), (uint8_t)gc->get(gc->DAY_OF_WEEK, status),
  209.         ((gc->get(gc->HOUR_OF_DAY, status) * 60 + gc->get(gc->MINUTE, status)) * 60 + gc->get(gc->SECOND, status)) * 1000 + gc->get(gc->MILLISECOND, status));
  210.     if (failure(status, "GregorianCalendar::get")) return;
  211.     if (offset == expDSTOffset) logln(UnicodeString("PASS: getOffset() = ") + (offset / ONE_HOUR));
  212.     else errln(UnicodeString("FAIL: getOffset() = ") + (offset / ONE_HOUR) + "; expected " + (expDSTOffset / ONE_HOUR));
  213.     delete gc;
  214. }
  215.  
  216. // -------------------------------------
  217.  
  218. /**
  219.  * Test the behavior of SimpleTimeZone at the transition into and out of DST.
  220.  * Use a binary search to find boundaries.
  221.  */
  222. void
  223. TimeZoneBoundaryTest::TestBoundaries()
  224. {
  225.     if (TRUE) {
  226.         logln("--- Test a ---");
  227.         UDate d = date(97, Calendar::APRIL, 6);
  228.         TimeZone *z = TimeZone::createTimeZone("PST");
  229.         for (int32_t i = 60; i <= 180; i += 15) {
  230.             bool_t inDST = (i >= 120);
  231.             UDate e = d + i * 60 * 1000;
  232.             verifyDST(e, z, TRUE, inDST, - 8 * ONE_HOUR, inDST ? - 7 * ONE_HOUR: - 8 * ONE_HOUR);
  233.         }
  234.         delete z;
  235.     }
  236.     if (TRUE) {
  237.         logln("--- Test b ---");
  238.         TimeZone *tz;
  239.         TimeZone::setDefault(*(tz = TimeZone::createTimeZone("PST")));
  240.         delete tz;
  241.         logln("========================================");
  242.         findDaylightBoundaryUsingDate(date(97, 0, 1), "PST", PST_1997_BEG);
  243.         logln("========================================");
  244.         findDaylightBoundaryUsingDate(date(97, 6, 1), "PDT", PST_1997_END);
  245.     }
  246.     if (TRUE) {
  247.         logln("--- Test c ---");
  248.         logln("========================================");
  249.         TimeZone* z = TimeZone::createTimeZone("Australia/Adelaide");
  250.         findDaylightBoundaryUsingTimeZone(date(97, 0, 1), TRUE, 859653000000.0, z);
  251.         logln("========================================");
  252.         findDaylightBoundaryUsingTimeZone(date(97, 6, 1), FALSE, 877797000000.0, z);
  253.         delete z;
  254.     }
  255.     if (TRUE) {
  256.         logln("--- Test d ---");
  257.         logln("========================================");
  258.         findDaylightBoundaryUsingTimeZone(date(97, 0, 1), FALSE, PST_1997_BEG);
  259.         logln("========================================");
  260.         findDaylightBoundaryUsingTimeZone(date(97, 6, 1), TRUE, PST_1997_END);
  261.     }
  262.     if (FALSE) {
  263.         logln("--- Test e ---");
  264.         TimeZone *z = TimeZone::createDefault();
  265.         logln(UnicodeString("") + z->getOffset(1, 97, 3, 4, 6, 0) + " " + date(97, 3, 4));
  266.         logln(UnicodeString("") + z->getOffset(1, 97, 3, 5, 7, 0) + " " + date(97, 3, 5));
  267.         logln(UnicodeString("") + z->getOffset(1, 97, 3, 6, 1, 0) + " " + date(97, 3, 6));
  268.         logln(UnicodeString("") + z->getOffset(1, 97, 3, 7, 2, 0) + " " + date(97, 3, 7));
  269.         delete z;
  270.     }
  271. }
  272.  
  273. // -------------------------------------
  274.  
  275. void
  276. TimeZoneBoundaryTest::testUsingBinarySearch(SimpleTimeZone* tz, UDate d, UDate expectedBoundary)
  277. {
  278.     UErrorCode status = U_ZERO_ERROR;
  279.     UDate min = d;
  280.     UDate max = min + SIX_MONTHS;
  281.     bool_t startsInDST = tz->inDaylightTime(d, status);
  282.     if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
  283.     if (tz->inDaylightTime(max, status) == startsInDST) {
  284.         logln("Error: inDaylightTime(" + dateToString(max) + ") != " + ((!startsInDST)?"true":"false"));
  285.     }
  286.     if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
  287.     while ((max - min) > INTERVAL) {
  288.         UDate mid = (min + max) / 2;
  289.         if (tz->inDaylightTime(mid, status) == startsInDST) {
  290.             min = mid;
  291.         }
  292.         else {
  293.             max = mid;
  294.         }
  295.         if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
  296.     }
  297.     logln("Binary Search Before: " + showDate(min));
  298.     logln("Binary Search After:  " + showDate(max));
  299.     UDate mindelta = expectedBoundary - min;
  300.     UDate maxdelta = max - expectedBoundary;
  301.     if (mindelta >= 0 &&
  302.         mindelta <= INTERVAL &&
  303.         mindelta >= 0 &&
  304.         mindelta <= INTERVAL) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary);
  305.     else errln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary);
  306. }
  307.  
  308. // -------------------------------------
  309.  
  310. /**
  311.  * Test the handling of the "new" rules; that is, rules other than nth Day of week.
  312.  */
  313. void
  314. TimeZoneBoundaryTest::TestNewRules()
  315. {
  316.     UErrorCode status = U_ZERO_ERROR;
  317.     if (TRUE) {
  318.         SimpleTimeZone *tz;
  319.         logln("-----------------------------------------------------------------");
  320.         logln("Aug 2ndTues .. Mar 15");
  321.         tz = new SimpleTimeZone(- 8 * (int32_t)ONE_HOUR, "Test_1", Calendar::AUGUST, 2, Calendar::TUESDAY, 2 * (int32_t)ONE_HOUR, Calendar::MARCH, 15, 0, 2 * (int32_t)ONE_HOUR, status);
  322.         logln("========================================");
  323.         testUsingBinarySearch(tz, date(97, 0, 1), 858416400000.0);
  324.         logln("========================================");
  325.         testUsingBinarySearch(tz, date(97, 6, 1), 871380000000.0);
  326.         delete tz;
  327.         logln("-----------------------------------------------------------------");
  328.         logln("Apr Wed>=14 .. Sep Sun<=20");
  329.         tz = new SimpleTimeZone(- 8 * (int32_t)ONE_HOUR, "Test_2", Calendar::APRIL, 14, - Calendar::WEDNESDAY, 2 *(int32_t)ONE_HOUR, Calendar::SEPTEMBER, - 20, - Calendar::SUNDAY, 2 * (int32_t)ONE_HOUR, status);
  330.         logln("========================================");
  331.         testUsingBinarySearch(tz, date(97, 0, 1), 861184800000.0);
  332.         logln("========================================");
  333.         testUsingBinarySearch(tz, date(97, 6, 1), 874227600000.0);
  334.         delete tz;
  335.     }
  336. }
  337.  
  338. // -------------------------------------
  339.  
  340. void
  341. TimeZoneBoundaryTest::findBoundariesStepwise(int32_t year, UDate interval, TimeZone* z, int32_t expectedChanges)
  342. {
  343.     UErrorCode status = U_ZERO_ERROR;
  344.     UnicodeString str;
  345.     UDate d = date(year - 1900, Calendar::JANUARY, 1);
  346.     UDate time = d;
  347.     UDate limit = time + ONE_YEAR + ONE_DAY;
  348.     bool_t lastState = z->inDaylightTime(d, status);
  349.     if (failure(status, "TimeZone::inDaylightTime")) return;
  350.     int32_t changes = 0;
  351.     logln(UnicodeString("-- Zone ") + z->getID(str) + " starts in " + year + " with DST = " + (lastState?"true":"false"));
  352.     logln(UnicodeString("useDaylightTime = ") + (z->useDaylightTime()?"true":"false"));
  353.     while (time < limit) {
  354.         d = time;
  355.         bool_t state = z->inDaylightTime(d, status);
  356.         if (failure(status, "TimeZone::inDaylightTime")) return;
  357.         if (state != lastState) {
  358.             logln(UnicodeString(state ? "Entry ": "Exit ") + "at " + d);
  359.             lastState = state;++changes;
  360.         }
  361.         time += interval;
  362.     }
  363.     if (changes == 0) {
  364.         if (!lastState &&
  365.             !z->useDaylightTime()) logln("No DST");
  366.         else errln("FAIL: DST all year, or no DST with true useDaylightTime");
  367.     }
  368.     else if (changes != 2) {
  369.         errln(UnicodeString("FAIL: ") + changes + " changes seen; should see 0 or 2");
  370.     }
  371.     else if (!z->useDaylightTime()) {
  372.         errln("FAIL: useDaylightTime false but 2 changes seen");
  373.     }
  374.     if (changes != expectedChanges) {
  375.         errln(UnicodeString("FAIL: ") + changes + " changes seen; expected " + expectedChanges);
  376.     }
  377. }
  378.  
  379. // -------------------------------------
  380.  
  381. /**
  382.  * Test the behavior of SimpleTimeZone at the transition into and out of DST.
  383.  * Use a stepwise march to find boundaries.
  384.  */ 
  385. void
  386. TimeZoneBoundaryTest::TestStepwise()
  387. {
  388.     TimeZone *zone =  TimeZone::createTimeZone("EST");
  389.     findBoundariesStepwise(1997, ONE_DAY, zone, 2);
  390.     delete zone;
  391.     zone = TimeZone::createTimeZone("ACT");
  392.     findBoundariesStepwise(1997, ONE_DAY, zone, 0);
  393.     delete zone;
  394.     zone = TimeZone::createTimeZone("Australia/Adelaide");
  395.     findBoundariesStepwise(1997, ONE_DAY, zone, 2);
  396.     delete zone;
  397. }
  398.