scdttime.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 12k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "ctlspriv.h"
  2. #include "scdttime.h"
  3. // BUGBUG? remove references to 1750 and 1752 as they
  4. // are not needed -- the minimal year we allow is 1753
  5. // to avoid such problems. (We don't care about
  6. // pre-revised-Gregorian dates! If you want to develop
  7. // a history application, then you can deal with these problems)
  8. int mpcdymoAccum[13] =
  9. { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
  10. /*
  11.  -    LIncrWord
  12.  -
  13.  *    Purpose:
  14.  *        Increment (or decrement) an integer by a specified amount,
  15.  *        given the constraints nMic and nMac.
  16.  *        Returns the amount of carry into the following (or preceding)
  17.  *        field, or zero if none.
  18.  *
  19.  *        Intended for use with incrementing date/times.
  20.  *
  21.  *    Arguments:
  22.  *        pn        Pointer to integer to be modified.
  23.  *        nDelta    Amount by which to modify *pn; may be positive,
  24.  *                negative or zero.
  25.  *        nMic    Minimum value for *pn;  if decrementing below this,
  26.  *                a carry is performed.
  27.  *        nMac    Maximum value for *pn;  if incrementing above this,
  28.  *                a carry is performed.
  29.  *
  30.  *    Returns:
  31.  *        Zero if modification done within constraints, otherwise the
  32.  *        amount of carry (positive in incrementing, negative if
  33.  *        decrementing).
  34.  *
  35.  */
  36. LONG LIncrWord(WORD *pn, LONG nDelta, int nMic, int nMac)
  37.     {
  38.     LONG lNew, lIncr;
  39.     lIncr = 0;
  40.     lNew = *pn + nDelta;
  41.     while (lNew >= nMac)
  42.         {
  43.         lNew -= nMac - nMic;
  44.         lIncr++;
  45.         }
  46.     if (!lIncr)
  47.         {
  48.         while (lNew < nMic)
  49.             {
  50.             lNew += nMac - nMic;
  51.             lIncr--;
  52.             }
  53.         }
  54.     *pn = (WORD)lNew;
  55.     return(lIncr);
  56.     }
  57. void IncrSystemTime(SYSTEMTIME *pstSrc, SYSTEMTIME *pstDest, LONG nDelta, LONG flag)
  58.     {
  59.     int cdyMon;
  60.     if (pstSrc != pstDest)
  61.         *pstDest = *pstSrc;
  62.     switch (flag)
  63.         {
  64.         case INCRSYS_SECOND:
  65.             if (!(nDelta = LIncrWord(&pstDest->wSecond, nDelta, 0, 60)))
  66.                 break;
  67.         case INCRSYS_MINUTE:
  68.             if (!(nDelta = LIncrWord(&pstDest->wMinute, nDelta, 0, 60)))
  69.                 break;
  70.         case INCRSYS_HOUR:
  71.             if (!(nDelta = LIncrWord(&pstDest->wHour, nDelta, 0, 24)))
  72.                 break;
  73.         case INCRSYS_DAY:
  74. IDTday:
  75.             if (nDelta >= 0)
  76.                 {
  77.                 cdyMon = GetDaysForMonth(pstDest->wYear, pstDest->wMonth);
  78.                 while (pstDest->wDay + nDelta > cdyMon)
  79.                     {
  80.                     nDelta -= cdyMon + 1 - pstDest->wDay;
  81.                     pstDest->wDay = 1;
  82.                     IncrSystemTime(pstDest, pstDest, 1, INCRSYS_MONTH);
  83.                     cdyMon = GetDaysForMonth(pstDest->wYear, pstDest->wMonth);
  84.                     }
  85.                 }
  86.             else
  87.                 {
  88.                 while (pstDest->wDay <= -nDelta)
  89.                     {
  90.                     nDelta += pstDest->wDay;
  91.                     IncrSystemTime(pstDest, pstDest, -1, INCRSYS_MONTH);
  92.                     cdyMon = GetDaysForMonth(pstDest->wYear, pstDest->wMonth);
  93.                     pstDest->wDay = (WORD) cdyMon;
  94.                     }
  95.                 }
  96.             pstDest->wDay += (WORD)nDelta;
  97.             break;
  98.         case INCRSYS_MONTH:
  99.             if (!(nDelta = LIncrWord(&pstDest->wMonth, nDelta, 1, 13)))
  100.                 {
  101.                 cdyMon = GetDaysForMonth(pstDest->wYear, pstDest->wMonth);
  102.                 if (pstDest->wDay > cdyMon)
  103.                     pstDest->wDay = (WORD) cdyMon;
  104.                 break;
  105.                 }
  106.         case INCRSYS_YEAR:
  107.             pstDest->wYear += (WORD)nDelta;
  108.             cdyMon = GetDaysForMonth(pstDest->wYear, pstDest->wMonth);
  109.             if (pstDest->wDay > cdyMon)
  110.                 pstDest->wDay = (WORD) cdyMon;
  111.             break;
  112.         case INCRSYS_WEEK:
  113.             nDelta *= 7;
  114.             goto IDTday;
  115.             break;
  116.         }
  117.     }
  118. CmpDate(const SYSTEMTIME *pst1, const SYSTEMTIME *pst2)
  119.     {
  120.     int iRet;
  121.     if (pst1->wYear < pst2->wYear)
  122.         iRet = -1;
  123.     else if (pst1->wYear > pst2->wYear)
  124.         iRet = 1;
  125.     else if (pst1->wMonth < pst2->wMonth)
  126.         iRet = -1;
  127.     else if (pst1->wMonth > pst2->wMonth)
  128.         iRet = 1;
  129.     else if (pst1->wDay < pst2->wDay)
  130.         iRet = -1;
  131.     else if (pst1->wDay > pst2->wDay)
  132.         iRet = 1;
  133.     else
  134.         iRet = 0;
  135.     return(iRet);
  136.     }
  137. CmpSystemtime(const SYSTEMTIME *pst1, const SYSTEMTIME *pst2)
  138.     {
  139.     int iRet;
  140.     if (pst1->wYear < pst2->wYear)
  141.         iRet = -1;
  142.     else if (pst1->wYear > pst2->wYear)
  143.         iRet = 1;
  144.     else if (pst1->wMonth < pst2->wMonth)
  145.         iRet = -1;
  146.     else if (pst1->wMonth > pst2->wMonth)
  147.         iRet = 1;
  148.     else if (pst1->wDay < pst2->wDay)
  149.         iRet = -1;
  150.     else if (pst1->wDay > pst2->wDay)
  151.         iRet = 1;
  152.     else if (pst1->wHour < pst2->wHour)
  153.         iRet = -1;
  154.     else if (pst1->wHour > pst2->wHour)
  155.         iRet = 1;
  156.     else if (pst1->wMinute < pst2->wMinute)
  157.         iRet = -1;
  158.     else if (pst1->wMinute > pst2->wMinute)
  159.         iRet = 1;
  160.     else if (pst1->wSecond < pst2->wSecond)
  161.         iRet = -1;
  162.     else if (pst1->wSecond > pst2->wSecond)
  163.         iRet = 1;
  164.     else
  165.         iRet = 0;
  166.     return(iRet);
  167.     }
  168. /*
  169.  -    CdyBetweenYmd
  170.  -
  171.  *    Purpose:
  172.  *        Calculate the number of days between two dates as expressed
  173.  *        in YMD's.
  174.  *
  175.  *    Parameters:
  176.  *        pymdStart        start day of range.
  177.  *        pymdEnd            end day of range.
  178.  *
  179.  *    Returns:
  180.  *        Number of days between two dates.  The number
  181.  *        of days does not include the starting day, but does include
  182.  *        the last day. ie 1/24/1990-1/25/1990 = 1 day.
  183.  */
  184. DWORD DaysBetweenDates(const SYSTEMTIME *pstStart, const SYSTEMTIME *pstEnd)
  185.     {
  186.     DWORD cday;
  187.     WORD yr;
  188.     // Calculate number of days between the start month/day and the
  189.     // end month/day as if they were in the same year - since cday
  190.     // is unsigned, cday could be really large if the end month/day
  191.     // is before the start month.day.
  192.     // This will be cleared up when we account for the days between
  193.     // the years.
  194.     ASSERT(pstEnd->wMonth >= 1 && pstEnd->wMonth <= 12);
  195.     cday = mpcdymoAccum[pstEnd->wMonth - 1] - mpcdymoAccum[pstStart->wMonth - 1] +
  196.              pstEnd->wDay - pstStart->wDay;
  197.     yr = pstStart->wYear;
  198.     // Check to see if the start year is before the end year,
  199.     // and if the end month is after February and
  200.     // if the end year is a leap year, then add an extra day
  201.     // for to account for Feb. 29 in the end year.
  202.     if ( ((yr < pstEnd->wYear) || (pstStart->wMonth <= 2)) &&
  203.          pstEnd->wMonth > 2 &&
  204.         (pstEnd->wYear & 03) == 0 &&
  205.         (pstEnd->wYear <= 1750 || pstEnd->wYear % 100 != 0 || pstEnd->wYear % 400 == 0))
  206.         {
  207.         cday++;
  208.         }
  209.     // Now account for the leap years in between the start and end dates
  210.     // as well as accounting for the days in each year.
  211.     if (yr < pstEnd->wYear)
  212.         {
  213.         // If the start date is before march and the start year is
  214.         // a leap year then add an extra day to account for Feb. 29.
  215.         if ( pstStart->wMonth <= 2 &&
  216.             (yr & 03) == 0 &&
  217.             (yr <= 1750 || yr % 100 != 0 || yr % 400 == 0))
  218.             {
  219.             cday++;
  220.             }
  221.         // Account for the days in each year (disregarding leap years).
  222.         cday += 365;
  223.         yr++;
  224.         // Keep on accounting for the days in each year including leap
  225.         // years until we reach the end year.
  226.         while (yr < pstEnd->wYear)
  227.             {
  228.             cday += 365;
  229.             if ((yr & 03) == 0 && (yr <= 1750 || yr % 100 != 0 || yr % 400 == 0))
  230.                 cday++;
  231.             yr++;
  232.             }
  233.         }
  234.     return(cday);
  235.     }
  236. /*
  237.  -    DowStartOfYrMo
  238.  -
  239.  *    Purpose:
  240.  *        Find the day of the week the indicated month begins on
  241.  *
  242.  *    Parameters:
  243.  *        yr        year, must be > 0
  244.  *        mo        month, number 1-12
  245.  *
  246.  *    Returns:
  247.  *        day of the week (0-6) on which the month begins
  248.  *        (0 = Sunday, 1 = Monday etc.)
  249.  */
  250. int GetStartDowForMonth(int yr, int mo)
  251.     {
  252.     int dow;
  253.     // we want monday = 0, sunday = 6
  254.     // dow = 6 + (yr - 1) + ((yr - 1) >> 2);
  255.     dow = 5 + (yr - 1) + ((yr - 1) >> 2);
  256.     if (yr > 1752)
  257.         dow += ((yr - 1) - 1600) / 400 - ((yr - 1) - 1700) / 100 - 11;
  258.     else if (yr == 1752 && mo > 9)
  259.         dow -= 11;
  260.     dow += mpcdymoAccum[mo - 1];
  261.     if (mo > 2 && (yr & 03) == 0 && (yr <= 1750 || yr % 100 != 0 || yr % 400 == 0))
  262.         dow++;
  263.     dow %= 7;
  264.     return(dow);
  265.     }
  266. int DowFromDate(const SYSTEMTIME *pst)
  267.     {
  268.     int dow;
  269.     dow = GetStartDowForMonth(pst->wYear, pst->wMonth);
  270.     dow = (dow + pst->wDay - 1) % 7;
  271.     return(dow);
  272.     }
  273. int GetDaysForMonth(int yr, int mo)
  274.     {
  275.     int cdy;
  276.     if (yr == 1752 && mo == 9)
  277.         return(19);
  278.     cdy = mpcdymoAccum[mo] - mpcdymoAccum[mo - 1];
  279.     if (mo == 2 && (yr & 03) == 0 && (yr <= 1750 || yr % 100 != 0 || yr % 400 == 0))
  280.         cdy++;
  281.     return(cdy);
  282.     }
  283. /*
  284.  -    NweekNumber
  285.  -
  286.  *    Purpose:
  287.  *        Calculates week number in which a given date occurs, based
  288.  *        on a specified start-day of week.
  289.  *        Adjusts based on how a calendar would show this week
  290.  *        (ie. week 53 is probably week 1 on the calendar).
  291.  *
  292.  *    Arguments:
  293.  *        pdtm            Pointer to date in question
  294.  *        dowStartWeek    Day-of-week on which weeks starts (0 - 6).
  295.  *
  296.  *    Returns:
  297.  *        Week number of the year, in which *pdtr occurs.
  298.  *
  299.  */
  300. // TODO: this currently ignores woyFirst
  301. // it uses the 1st week containing 4+ days as the first week (woyFirst = 2)
  302. // need to make appropriate changes so it handles woyFirst = 0 and = 1...
  303. int GetWeekNumber(const SYSTEMTIME *pst, int dowFirst, int woyFirst)
  304.     {
  305.     int day, ddow, ddowT, nweek;
  306.     SYSTEMTIME st;
  307.     
  308.     st.wYear = pst->wYear;
  309.     st.wMonth = 1;
  310.     st.wDay = 1;
  311.     ddow = GetStartDowForMonth(st.wYear, st.wMonth) - dowFirst;
  312.     if (ddow < 0)
  313.         ddow += 7;
  314.     if (pst->wMonth == 1 && pst->wDay < 8 - ddow)
  315.         {
  316.         nweek = 0;
  317.         }
  318.     else
  319.         {
  320.         if (ddow)
  321.             st.wDay = 8 - ddow;
  322.         nweek = (DaysBetweenDates(&st, pst) / 7) + 1;
  323.         }
  324.     if (ddow && ddow <= 3)
  325.         nweek++;
  326.     // adjust if necessary for calendar
  327.     if (!nweek)
  328.         {
  329.         if (!ddow)
  330.             return(1);
  331.         // check what week Dec 31 is on
  332.         st.wYear--;
  333.         st.wMonth = 12;
  334.         st.wDay = 31;
  335.         return(GetWeekNumber(&st, dowFirst, woyFirst));
  336.         }
  337.     else if (nweek >= 52)
  338.         {
  339.         ddowT = (GetStartDowForMonth(pst->wYear, pst->wMonth) +
  340.                     pst->wDay - 1 + 7 -    dowFirst) % 7;
  341.         day = pst->wDay + (7 - ddowT);
  342.         if (day > 31 + 4)
  343.             nweek = 1;
  344.         }
  345.     return(nweek);
  346.     }
  347. // ignores day of week and time-related fields...
  348. // BUGBUG also validate years in range
  349. BOOL IsValidDate(const SYSTEMTIME *pst)
  350.     {
  351.     int cDay;
  352.     if (pst && pst->wMonth >= 1 && pst->wMonth <= 12)
  353.         {
  354.         cDay = GetDaysForMonth(pst->wYear, pst->wMonth);
  355.         if (pst->wDay >= 1 && pst->wDay <= cDay)
  356.             return(TRUE);
  357.         }
  358.     return(FALSE);
  359.     }
  360. // ignores milliseconds and date-related fields...
  361. BOOL IsValidTime(const SYSTEMTIME *pst)
  362.     {
  363.     return(pst->wHour <= 23 &&
  364.             pst->wMinute <= 59 &&
  365.             pst->wSecond <= 59);
  366.     }
  367. // ignores day of week
  368. BOOL IsValidSystemtime(const SYSTEMTIME *pst)
  369.     {
  370.     if (pst && pst->wMonth >= 1 && pst->wMonth <= 12)
  371.         {
  372.         int cDay = GetDaysForMonth(pst->wYear, pst->wMonth);
  373.         if (pst->wDay >= 1 &&
  374.             pst->wDay <= cDay &&
  375.             pst->wHour <= 23 &&
  376.             pst->wMinute <= 59 &&
  377.             pst->wSecond <= 59 &&
  378.             pst->wMilliseconds < 1000)
  379.             return(TRUE);
  380.         }
  381.     return(FALSE);
  382.     }