mux/src/timeutil.cpp

Go to the documentation of this file.
00001 
00017 #include "copyright.h"
00018 #include "autoconf.h"
00019 #include "config.h"
00020 #include "externs.h"
00021 
00022 // for tzset() and localtime()
00023 //
00024 #include <time.h>
00025 
00026 #include "timeutil.h"
00027 #include "stringutil.h"
00028 
00029 CMuxAlarm MuxAlarm;
00030 
00031 #ifdef SMALLEST_INT_GTE_NEG_QUOTIENT
00032 
00033 // The following functions provide a consistent division/modulus function
00034 // regardless of how the platform chooses to provide this function.
00035 //
00036 // Confused yet? Here's an example:
00037 //
00038 // SMALLEST_INT_GTE_NEG_QUOTIENT indicates that this platform computes
00039 // division and modulus like so:
00040 //
00041 //   -9/5 ==> -1 and -9%5 ==> -4
00042 //   and (-9/5)*5 + (-9%5) ==> -1*5 + -4 ==> -5 + -4 ==> -9
00043 //
00044 // The iMod() function uses this to provide LARGEST_INT_LTE_NEG_QUOTIENT
00045 // behavior (required by much math). This behavior computes division and
00046 // modulus like so:
00047 //
00048 //   -9/5 ==> -2 and -9%5 ==> 1
00049 //   and (-9/5)*5 + (-9%5) ==> -2*5 + 1 ==> -10 + 1 ==> -9
00050 //
00051 
00052 // Provide LLEQ modulus on a SGEQ platform.
00053 //
00054 int iMod(int x, int y)
00055 {
00056     if (y < 0)
00057     {
00058         if (x <= 0)
00059         {
00060             return x % y;
00061         }
00062         else
00063         {
00064             return ((x-1) % y) + y + 1;
00065         }
00066     }
00067     else
00068     {
00069         if (x < 0)
00070         {
00071             return ((x+1) % y) + y - 1;
00072         }
00073         else
00074         {
00075             return x % y;
00076         }
00077     }
00078 }
00079 
00080 INT64 i64Mod(INT64 x, INT64 y)
00081 {
00082     if (y < 0)
00083     {
00084         if (x <= 0)
00085         {
00086             return x % y;
00087         }
00088         else
00089         {
00090             return ((x-1) % y) + y + 1;
00091         }
00092     }
00093     else
00094     {
00095         if (x < 0)
00096         {
00097             return ((x+1) % y) + y - 1;
00098         }
00099         else
00100         {
00101             return x % y;
00102         }
00103     }
00104 }
00105 
00106 // Provide SGEQ modulus on a SGEQ platform.
00107 //
00108 DCL_INLINE int iRemainder(int x, int y)
00109 {
00110     return x % y;
00111 }
00112 
00113 // Provide SGEQ division on a SGEQ platform.
00114 //
00115 DCL_INLINE int iDivision(int x, int y)
00116 {
00117     return x / y;
00118 }
00119 
00120 // Provide LLEQ division on a SGEQ platform.
00121 //
00122 static int iFloorDivision(int x, int y)
00123 {
00124     if (y < 0)
00125     {
00126         if (x <= 0)
00127         {
00128             return x / y;
00129         }
00130         else
00131         {
00132             return (x - y - 1) / y;
00133         }
00134     }
00135     else
00136     {
00137         if (x < 0)
00138         {
00139             return (x - y + 1) / y;
00140         }
00141         else
00142         {
00143             return x / y;
00144         }
00145     }
00146 }
00147 
00148 INT64 i64FloorDivision(INT64 x, INT64 y)
00149 {
00150     if (y < 0)
00151     {
00152         if (x <= 0)
00153         {
00154             return x / y;
00155         }
00156         else
00157         {
00158             return (x - y - 1) / y;
00159         }
00160     }
00161     else
00162     {
00163         if (x < 0)
00164         {
00165             return (x - y + 1) / y;
00166         }
00167         else
00168         {
00169             return x / y;
00170         }
00171     }
00172 }
00173 
00174 int iFloorDivisionMod(int x, int y, int *piMod)
00175 {
00176     if (y < 0)
00177     {
00178         if (x <= 0)
00179         {
00180             *piMod = x % y;
00181             return x / y;
00182         }
00183         else
00184         {
00185             *piMod = ((x-1) % y) + y + 1;
00186             return (x - y - 1) / y;
00187         }
00188     }
00189     else
00190     {
00191         if (x < 0)
00192         {
00193             *piMod = ((x+1) % y) + y - 1;
00194             return (x - y + 1) / y;
00195         }
00196         else
00197         {
00198             *piMod = x % y;
00199             return x / y;
00200         }
00201     }
00202 }
00203 
00204 static INT64 i64FloorDivisionMod(INT64 x, INT64 y, INT64 *piMod)
00205 {
00206     if (y < 0)
00207     {
00208         if (x <= 0)
00209         {
00210             *piMod = x % y;
00211             return x / y;
00212         }
00213         else
00214         {
00215             *piMod = ((x-1) % y) + y + 1;
00216             return (x - y - 1) / y;
00217         }
00218     }
00219     else
00220     {
00221         if (x < 0)
00222         {
00223             *piMod = ((x+1) % y) + y - 1;
00224             return (x - y + 1) / y;
00225         }
00226         else
00227         {
00228             *piMod = x % y;
00229             return x / y;
00230         }
00231     }
00232 }
00233 
00234 #if 0
00235 int iCeilingDivision(int x, int y)
00236 {
00237     if (x < 0)
00238     {
00239         return x / y;
00240     }
00241     else
00242     {
00243         return (x + y - 1) / y;
00244     }
00245 }
00246 
00247 INT64 i64CeilingDivision(INT64 x, INT64 y)
00248 {
00249     if (x < 0)
00250     {
00251         return x / y;
00252     }
00253     else
00254     {
00255         return (x + y - 1) / y;
00256     }
00257 }
00258 #endif // 0
00259 
00260 #else // LARGEST_INT_LTE_NEG_QUOTIENT
00261 
00262 // Provide LLEQ modulus on a LLEQ platform.
00263 //
00264 int DCL_INLINE iMod(int x, int y)
00265 {
00266     return x % y;
00267 }
00268 
00269 // Provide a SGEQ modulus on a LLEQ platform.
00270 //
00271 int iRemainder(int x, int y)
00272 {
00273     if (y < 0)
00274     {
00275         if (x <= 0)
00276         {
00277             return x % y;
00278         }
00279         else
00280         {
00281             return ((x+1) % y) - y - 1;
00282         }
00283     }
00284     else
00285     {
00286         if (x < 0)
00287         {
00288             return ((x-1) % y) - y + 1;
00289         }
00290         else
00291         {
00292             return x % y;
00293         }
00294     }
00295 }
00296 
00297 INT64 i64Remainder(INT64 x, INT64 y)
00298 {
00299     if (y < 0)
00300     {
00301         if (x <= 0)
00302         {
00303             return x % y;
00304         }
00305         else
00306         {
00307             return ((x+1) % y) - y - 1;
00308         }
00309     }
00310     else
00311     {
00312         if (x < 0)
00313         {
00314             return ((x-1) % y) - y + 1;
00315         }
00316         else
00317         {
00318             return x % y;
00319         }
00320     }
00321 }
00322 
00323 // Provide SGEQ division on a LLEQ platform.
00324 //
00325 int iDivision(int x, int y)
00326 {
00327     if (y < 0)
00328     {
00329         if (x <= 0)
00330         {
00331             return x / y;
00332         }
00333         else
00334         {
00335             return (x + y + 1) / y;
00336         }
00337     }
00338     else
00339     {
00340         if (x < 0)
00341         {
00342             return (x + y - 1) / y;
00343         }
00344         else
00345         {
00346             return x / y;
00347         }
00348     }
00349 }
00350 
00351 INT64 i64Division(INT64 x, INT64 y)
00352 {
00353     if (y < 0)
00354     {
00355         if (x <= 0)
00356         {
00357             return x / y;
00358         }
00359         else
00360         {
00361             return (x + y + 1) / y;
00362         }
00363     }
00364     else
00365     {
00366         if (x < 0)
00367         {
00368             return (x + y - 1) / y;
00369         }
00370         else
00371         {
00372             return x / y;
00373         }
00374     }
00375 }
00376 
00377 // Provide a LLEQ division on a LLEQ platform.
00378 //
00379 int DCL_INLINE iFloorDivision(int x, int y)
00380 {
00381     return x / y;
00382 }
00383 
00384 INT64 DCL_INLINE i64FloorDivisionMod(INT64 x, INT64 y, INT64 *piMod)
00385 {
00386     *piMod = x % y;
00387     return x / y;
00388 }
00389 #endif // LARGEST_INT_LTE_NEG_QUOTIENT
00390 
00391 #if 0
00392 static int iModAdjusted(int x, int y)
00393 {
00394     return iMod(x - 1, y) + 1;
00395 }
00396 
00397 static INT64 i64ModAdjusted(INT64 x, INT64 y)
00398 {
00399     return i64Mod(x - 1, y) + 1;
00400 }
00401 #endif // 0
00402 
00403 #ifdef WIN32
00404 const INT64 FACTOR_100NS_PER_SECOND = 10000000i64;
00405 #else // WIN32
00406 const INT64 FACTOR_100NS_PER_SECOND = 10000000ull;
00407 #endif // WIN32
00408 const INT64 FACTOR_100NS_PER_MINUTE = FACTOR_100NS_PER_SECOND*60;
00409 const INT64 FACTOR_100NS_PER_HOUR   = FACTOR_100NS_PER_MINUTE*60;
00410 const INT64 FACTOR_100NS_PER_DAY = FACTOR_100NS_PER_HOUR*24;
00411 const INT64 FACTOR_100NS_PER_WEEK = FACTOR_100NS_PER_DAY*7;
00412 
00413 int CLinearTimeAbsolute::m_nCount = 0;
00414 char CLinearTimeAbsolute::m_Buffer[204];
00415 char CLinearTimeDelta::m_Buffer[204];
00416 
00417 static void GetUTCLinearTime(INT64 *plt);
00418 
00419 bool operator<(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb)
00420 {
00421     return lta.m_tAbsolute < ltb.m_tAbsolute;
00422 }
00423 
00424 bool operator>(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb)
00425 {
00426     return lta.m_tAbsolute > ltb.m_tAbsolute;
00427 }
00428 
00429 bool operator==(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb)
00430 {
00431     return lta.m_tAbsolute == ltb.m_tAbsolute;
00432 }
00433 
00434 bool operator==(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb)
00435 {
00436     return lta.m_tDelta == ltb.m_tDelta;
00437 }
00438 
00439 bool operator!=(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb)
00440 {
00441     return lta.m_tDelta != ltb.m_tDelta;
00442 }
00443 
00444 bool operator<=(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb)
00445 {
00446     return lta.m_tDelta <= ltb.m_tDelta;
00447 }
00448 
00449 bool operator<=(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb)
00450 {
00451     return lta.m_tAbsolute <= ltb.m_tAbsolute;
00452 }
00453 
00454 CLinearTimeAbsolute operator-(const CLinearTimeAbsolute& lta, const CLinearTimeDelta& ltd)
00455 {
00456     CLinearTimeAbsolute t;
00457     t.m_tAbsolute = lta.m_tAbsolute - ltd.m_tDelta;
00458     return t;
00459 }
00460 
00461 CLinearTimeAbsolute::CLinearTimeAbsolute(const CLinearTimeAbsolute& ltaOrigin, const CLinearTimeDelta& ltdOffset)
00462 {
00463     m_tAbsolute = ltaOrigin.m_tAbsolute + ltdOffset.m_tDelta;
00464 }
00465 
00466 static bool ParseFractionalSecondsString(INT64 &i64, char *str)
00467 {
00468     bool bMinus = false;
00469 
00470     i64 = 0;
00471 
00472     bool bGotOne;
00473 
00474     // Leading spaces.
00475     //
00476     while (mux_isspace(*str))
00477     {
00478         str++;
00479     }
00480 
00481     // Leading minus
00482     //
00483     if (*str == '-')
00484     {
00485         bMinus = true;
00486         str++;
00487 
00488         // But not if just a minus
00489         //
00490         if (!*str)
00491         {
00492             return false;
00493         }
00494     }
00495 
00496     // Need at least one digit.
00497     //
00498     bGotOne = false;
00499     char *pIntegerStart = str;
00500     if (mux_isdigit(*str))
00501     {
00502         bGotOne = true;
00503         str++;
00504     }
00505 
00506     // The number (int)
00507     //
00508     while (mux_isdigit(*str))
00509     {
00510         str++;
00511     }
00512     char *pIntegerEnd = str;
00513 
00514     // Decimal point.
00515     //
00516     if (*str == '.')
00517     {
00518         str++;
00519     }
00520 
00521     // Need at least one digit
00522     //
00523     char *pFractionalStart = str;
00524     if (mux_isdigit(*str))
00525     {
00526         bGotOne = true;
00527         str++;
00528     }
00529 
00530     // The number (fract)
00531     //
00532     while (mux_isdigit(*str))
00533     {
00534         str++;
00535     }
00536     char *pFractionalEnd = str;
00537 
00538     // Trailing spaces.
00539     //
00540     while (mux_isspace(*str))
00541     {
00542         str++;
00543     }
00544 
00545     if (*str || !bGotOne)
00546     {
00547         return false;
00548     }
00549 
00550 #define PFSS_PRECISION 7
00551     char   aBuffer[64];
00552     size_t nBufferAvailable = sizeof(aBuffer) - PFSS_PRECISION - 1;
00553     char  *p = aBuffer;
00554 
00555     // Sign.
00556     //
00557     if (bMinus)
00558     {
00559         *p++ = '-';
00560         nBufferAvailable--;
00561     }
00562 
00563     // Integer part.
00564     //
00565     bool bOverUnderflow = false;
00566     size_t n = pIntegerEnd - pIntegerStart;
00567     if (n > 0)
00568     {
00569         if (n > nBufferAvailable)
00570         {
00571             bOverUnderflow = true;
00572             n = nBufferAvailable;
00573         }
00574         memcpy(p, pIntegerStart, n);
00575         p += n;
00576         nBufferAvailable -= n;
00577     }
00578 
00579     // Fractional part.
00580     //
00581     n = pFractionalEnd - pFractionalStart;
00582     if (n > 0)
00583     {
00584         if (n > PFSS_PRECISION)
00585         {
00586             n = PFSS_PRECISION;
00587         }
00588         memcpy(p, pFractionalStart, n);
00589         p += n;
00590         nBufferAvailable -= n;
00591     }
00592 
00593     // Handle trailing zeroes.
00594     //
00595     n = PFSS_PRECISION - n;
00596     if (n > 0)
00597     {
00598         memset(p, '0', n);
00599         p += n;
00600     }
00601     *p++ = '\0';
00602 
00603     if (bOverUnderflow)
00604     {
00605         if (bMinus)
00606         {
00607             i64 = INT64_MIN_VALUE;
00608         }
00609         else
00610         {
00611             i64 = INT64_MAX_VALUE;
00612         }
00613     }
00614     else
00615     {
00616         i64 = mux_atoi64(aBuffer);
00617     }
00618     return true;
00619 }
00620 
00621 static void ConvertToSecondsString(char *buffer, INT64 n64, int nFracDigits)
00622 {
00623     INT64 Leftover;
00624     INT64 lt = i64FloorDivisionMod(n64, FACTOR_100NS_PER_SECOND, &Leftover);
00625 
00626     size_t n = mux_i64toa(lt, buffer);
00627     if (Leftover == 0)
00628     {
00629         return;
00630     }
00631 
00632     // Sanitize Precision Request.
00633     //
00634     const int maxFracDigits = 7;
00635     const int minFracDigits = 0;
00636     if (nFracDigits < minFracDigits)
00637     {
00638         nFracDigits = minFracDigits;
00639     }
00640     else if (maxFracDigits < nFracDigits)
00641     {
00642         nFracDigits = maxFracDigits;
00643     }
00644     if (0 < nFracDigits)
00645     {
00646         char *p = buffer + n;
00647         *p++ = '.';
00648         char *q = p;
00649 
00650         char buf[maxFracDigits+1];
00651         size_t m = mux_i64toa(Leftover, buf);
00652         memset(p, '0', maxFracDigits - m);
00653         p += maxFracDigits - m;
00654         memcpy(p, buf, m);
00655         p = q + nFracDigits - 1;
00656         while (*p == '0')
00657         {
00658             p--;
00659         }
00660         p++;
00661         *p = '\0';
00662     }
00663 }
00664 
00665 char *CLinearTimeDelta::ReturnSecondsString(int nFracDigits)
00666 {
00667     ConvertToSecondsString(m_Buffer, m_tDelta, nFracDigits);
00668     return m_Buffer;
00669 }
00670 
00671 char *CLinearTimeAbsolute::ReturnSecondsString(int nFracDigits)
00672 {
00673     ConvertToSecondsString(m_Buffer, m_tAbsolute - EPOCH_OFFSET, nFracDigits);
00674     return m_Buffer;
00675 }
00676 
00677 CLinearTimeAbsolute::CLinearTimeAbsolute(const CLinearTimeAbsolute &lta)
00678 {
00679     m_tAbsolute = lta.m_tAbsolute;
00680 }
00681 
00682 CLinearTimeAbsolute::CLinearTimeAbsolute(void)
00683 {
00684     m_tAbsolute = 0;
00685 }
00686 
00687 CLinearTimeDelta::CLinearTimeDelta(void)
00688 {
00689     m_tDelta = 0;
00690 }
00691 
00692 CLinearTimeDelta::CLinearTimeDelta(INT64 arg_t100ns)
00693 {
00694     m_tDelta = arg_t100ns;
00695 }
00696 
00697 void CLinearTimeDelta::ReturnTimeValueStruct(struct timeval *tv)
00698 {
00699     INT64 Leftover;
00700     tv->tv_sec = (long)i64FloorDivisionMod(m_tDelta, FACTOR_100NS_PER_SECOND, &Leftover);
00701     tv->tv_usec = (long)i64FloorDivision(Leftover, FACTOR_100NS_PER_MICROSECOND);
00702 }
00703 
00704 #ifdef HAVE_NANOSLEEP
00705 void CLinearTimeDelta::ReturnTimeSpecStruct(struct timespec *ts)
00706 {
00707     INT64 Leftover;
00708     ts->tv_sec = (long)i64FloorDivisionMod(m_tDelta, FACTOR_100NS_PER_SECOND, &Leftover);
00709     ts->tv_nsec = (long)Leftover*FACTOR_NANOSECONDS_PER_100NS;
00710 }
00711 #endif // HAVE_NANOSLEEP
00712 
00713 void CLinearTimeDelta::SetTimeValueStruct(struct timeval *tv)
00714 {
00715     m_tDelta = FACTOR_100NS_PER_SECOND * tv->tv_sec
00716              + FACTOR_100NS_PER_MICROSECOND * tv->tv_usec;
00717 }
00718 
00719 // Time string format is usually 24 characters long, in format
00720 // Ddd Mmm DD HH:MM:SS YYYY
00721 //
00722 // However, the year may be larger than 4 characters.
00723 //
00724 
00725 char *DayOfWeekString[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00726 static const char daystab[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00727 const char *monthtab[] =
00728 {
00729     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00730 };
00731 
00732 void CLinearTimeDelta::SetMilliseconds(unsigned long arg_dwMilliseconds)
00733 {
00734     m_tDelta = arg_dwMilliseconds * FACTOR_100NS_PER_MILLISECOND;
00735 }
00736 
00737 long CLinearTimeDelta::ReturnMilliseconds(void)
00738 {
00739     return (long)(m_tDelta/FACTOR_100NS_PER_MILLISECOND);
00740 }
00741 
00742 INT64 CLinearTimeDelta::ReturnMicroseconds(void)
00743 {
00744     return m_tDelta/FACTOR_100NS_PER_MICROSECOND;
00745 }
00746 
00747 void CLinearTimeDelta::SetSecondsString(char *arg_szSeconds)
00748 {
00749     ParseFractionalSecondsString(m_tDelta, arg_szSeconds);
00750 }
00751 
00752 void CLinearTimeDelta::SetSeconds(INT64 arg_tSeconds)
00753 {
00754     m_tDelta = arg_tSeconds * FACTOR_100NS_PER_SECOND;
00755 }
00756 
00757 void CLinearTimeDelta::Set100ns(INT64 arg_t100ns)
00758 {
00759     m_tDelta = arg_t100ns;
00760 }
00761 
00762 INT64 CLinearTimeDelta::Return100ns(void)
00763 {
00764     return m_tDelta;
00765 }
00766 
00767 void CLinearTimeAbsolute::Set100ns(INT64 arg_t100ns)
00768 {
00769     m_tAbsolute = arg_t100ns;
00770 }
00771 
00772 INT64 CLinearTimeAbsolute::Return100ns(void)
00773 {
00774     return m_tAbsolute;
00775 }
00776 
00777 void CLinearTimeAbsolute::SetSeconds(INT64 arg_tSeconds)
00778 {
00779     m_tAbsolute = arg_tSeconds;
00780     m_tAbsolute *= FACTOR_100NS_PER_SECOND;
00781 
00782     // Epoch difference between (00:00:00 UTC, January 1, 1970) and
00783     // (00:00:00 UTC, January 1, 1601).
00784     //
00785     m_tAbsolute += EPOCH_OFFSET;
00786 }
00787 
00788 INT64 CLinearTimeAbsolute::ReturnSeconds(void)
00789 {
00790     // INT64 is in hundreds of nanoseconds.
00791     // And the Epoch is 0:00 1/1/1601 instead of 0:00 1/1/1970
00792     //
00793     return i64FloorDivision(m_tAbsolute - EPOCH_OFFSET, FACTOR_100NS_PER_SECOND);
00794 }
00795 
00796 bool isLeapYear(long iYear)
00797 {
00798     if (iMod(iYear, 4) != 0)
00799     {
00800         // Not a leap year.
00801         //
00802         return false;
00803     }
00804     unsigned long wMod = iMod(iYear, 400);
00805     if ((wMod == 100) || (wMod == 200) || (wMod == 300))
00806     {
00807         // Not a leap year.
00808         //
00809         return false;
00810     }
00811     return true;
00812 }
00813 
00814 static bool isValidDate(int iYear, int iMonth, int iDay)
00815 {
00816     if (iYear < -27256 || 30826 < iYear)
00817     {
00818         return false;
00819     }
00820     if (iMonth < 1 || 12 < iMonth)
00821     {
00822         return false;
00823     }
00824     if (iDay < 1 || daystab[iMonth-1] < iDay)
00825     {
00826         return false;
00827     }
00828     if (iMonth == 2 && iDay == 29 && !isLeapYear(iYear))
00829     {
00830         return false;
00831     }
00832     return true;
00833 }
00834 
00835 static int FixedFromGregorian(int iYear, int iMonth, int iDay)
00836 {
00837     iYear = iYear - 1;
00838     int iFixedDay = 365 * iYear;
00839     iFixedDay += iFloorDivision(iYear, 4);
00840     iFixedDay -= iFloorDivision(iYear, 100);
00841     iFixedDay += iFloorDivision(iYear, 400);
00842     iFixedDay += iFloorDivision(367 * iMonth - 362, 12);
00843     iFixedDay += iDay;
00844 
00845     if (iMonth > 2)
00846     {
00847         if (isLeapYear(iYear+1))
00848         {
00849             iFixedDay -= 1;
00850         }
00851         else
00852         {
00853             iFixedDay -= 2;
00854         }
00855     }
00856 
00857     // At this point, iFixedDay has an epoch of 1 R.D.
00858     //
00859     return iFixedDay;
00860 }
00861 
00862 static int FixedFromGregorian_Adjusted(int iYear, int iMonth, int iDay)
00863 {
00864     int iFixedDay = FixedFromGregorian(iYear, iMonth, iDay);
00865 
00866     // At this point, iFixedDay has an epoch of 1 R.D.
00867     // We need an Epoch of (00:00:00 UTC, January 1, 1601)
00868     //
00869     return iFixedDay - 584389;
00870 }
00871 
00872 
00873 // Epoch of iFixedDay should be 1 R.D.
00874 //
00875 static void GregorianFromFixed(int iFixedDay, int &iYear, int &iMonth,  int &iDayOfYear, int &iDayOfMonth, int &iDayOfWeek)
00876 {
00877     int d0 = iFixedDay - 1;
00878     int d1, n400 = iFloorDivisionMod(d0, 146097, &d1);
00879     int d2, n100 = iFloorDivisionMod(d1,  36524, &d2);
00880     int d3, n4   = iFloorDivisionMod(d2,   1461, &d3);
00881     int d4, n1   = iFloorDivisionMod(d3,    365, &d4);
00882     d4 = d4 + 1;
00883 
00884     iYear = 400*n400 + 100*n100 + 4*n4 + n1;
00885 
00886     if (n100 != 4 && n1 != 4)
00887     {
00888         iYear = iYear + 1;
00889     }
00890 
00891     static int cache_iYear = 99999;
00892     static int cache_iJan1st = 0;
00893     static int cache_iMar1st = 0;
00894     int iFixedDayOfJanuary1st;
00895     int iFixedDayOfMarch1st;
00896     if (iYear == cache_iYear)
00897     {
00898         iFixedDayOfJanuary1st = cache_iJan1st;
00899         iFixedDayOfMarch1st = cache_iMar1st;
00900     }
00901     else
00902     {
00903         cache_iYear = iYear;
00904         cache_iJan1st = iFixedDayOfJanuary1st = FixedFromGregorian(iYear, 1, 1);
00905         cache_iMar1st = iFixedDayOfMarch1st = FixedFromGregorian(iYear, 3, 1);
00906     }
00907 
00908 
00909     int iPriorDays = iFixedDay - iFixedDayOfJanuary1st;
00910     int iCorrection;
00911     if (iFixedDay < iFixedDayOfMarch1st)
00912     {
00913         iCorrection = 0;
00914     }
00915     else if (isLeapYear(iYear))
00916     {
00917         iCorrection = 1;
00918     }
00919     else
00920     {
00921         iCorrection = 2;
00922     }
00923 
00924     iMonth = (12*(iPriorDays+iCorrection)+373)/367;
00925     iDayOfMonth = iFixedDay - FixedFromGregorian(iYear, iMonth, 1) + 1;
00926     iDayOfYear = iPriorDays + 1;
00927 
00928     // Calculate the Day of week using the linear progression of days.
00929     //
00930     iDayOfWeek = iMod(iFixedDay, 7);
00931 }
00932 
00933 static void GregorianFromFixed_Adjusted(int iFixedDay, int &iYear, int &iMonth, int &iDayOfYear, int &iDayOfMonth, int &iDayOfWeek)
00934 {
00935     // We need to convert the Epoch to 1 R.D. from
00936     // (00:00:00 UTC, January 1, 1601)
00937     //
00938     GregorianFromFixed(iFixedDay + 584389, iYear, iMonth, iDayOfYear, iDayOfMonth, iDayOfWeek);
00939 }
00940 
00941 // do_convtime()
00942 //
00943 // converts time string to time structure (fielded time). Returns 1 on
00944 // success, 0 on fail. Time string format is:
00945 //
00946 //     [Ddd] Mmm DD HH:MM:SS YYYY
00947 //
00948 // The initial Day-of-week token is optional.
00949 //
00950 static int MonthTabHash[12] =
00951 {
00952     0x004a414e, 0x00464542, 0x004d4152, 0x00415052,
00953     0x004d4159, 0x004a554e, 0x004a554c, 0x00415547,
00954     0x00534550, 0x004f4354, 0x004e4f56, 0x00444543
00955 };
00956 
00957 static bool ParseThreeLetters(const char **pp, int *piHash)
00958 {
00959     *piHash = 0;
00960 
00961     // Skip Initial spaces
00962     //
00963     const char *p = *pp;
00964     while (*p == ' ')
00965     {
00966         p++;
00967     }
00968 
00969     // Parse space-separate token.
00970     //
00971     const char *q = p;
00972     int iHash = 0;
00973     while (*q && *q != ' ')
00974     {
00975         if (!mux_isalpha(*q))
00976         {
00977             return false;
00978         }
00979         iHash = (iHash << 8) | mux_toupper(*q);
00980         q++;
00981     }
00982 
00983     // Must be exactly 3 letters long.
00984     //
00985     if (q - p != 3)
00986     {
00987         return false;
00988     }
00989     p = q;
00990 
00991     // Skip final spaces
00992     //
00993     while (*p == ' ')
00994     {
00995         p++;
00996     }
00997 
00998     *pp = p;
00999     *piHash = iHash;
01000     return true;
01001 }
01002 
01003 static void ParseDecimalSeconds(size_t n, const char *p, unsigned short *iMilli,
01004                          unsigned short *iMicro, unsigned short *iNano)
01005 {
01006    char aBuffer[10];
01007    if (n > sizeof(aBuffer) - 1)
01008    {
01009        n = sizeof(aBuffer) - 1;
01010    }
01011    memcpy(aBuffer, p, n);
01012    memset(aBuffer + n, '0', sizeof(aBuffer) - n - 1);
01013    aBuffer[sizeof(aBuffer) - 1] = '\0';
01014    int ns = mux_atol(aBuffer);
01015    *iNano = ns % 1000;
01016    ns /= 1000;
01017    *iMicro = ns % 1000;
01018    *iMilli = ns / 1000;
01019 }
01020 
01021 static bool do_convtime(const char *str, FIELDEDTIME *ft)
01022 {
01023     memset(ft, 0, sizeof(FIELDEDTIME));
01024     if (!str || !ft)
01025     {
01026         return false;
01027     }
01028 
01029     // Day-of-week OR month.
01030     //
01031     const char *p = str;
01032     int i, iHash;
01033     if (!ParseThreeLetters(&p, &iHash))
01034     {
01035         return false;
01036     }
01037     for (i = 0; (i < 12) && iHash != MonthTabHash[i]; i++) ;
01038     if (i == 12)
01039     {
01040         // The above three letters were probably the Day-Of-Week, the
01041         // next three letters are required to be the month name.
01042         //
01043         if (!ParseThreeLetters(&p, &iHash))
01044         {
01045             return false;
01046         }
01047         for (i = 0; (i < 12) && iHash != MonthTabHash[i]; i++) ;
01048         if (i == 12)
01049         {
01050             return false;
01051         }
01052     }
01053     ft->iMonth = i + 1; // January = 1, February = 2, etc.
01054 
01055     // Day of month.
01056     //
01057     ft->iDayOfMonth = (unsigned short)mux_atol(p);
01058     if (ft->iDayOfMonth < 1 || daystab[i] < ft->iDayOfMonth)
01059     {
01060         return false;
01061     }
01062     while (*p && *p != ' ') p++;
01063     while (*p == ' ') p++;
01064 
01065     // Hours
01066     //
01067     ft->iHour = (unsigned short)mux_atol(p);
01068     if (ft->iHour > 23 || (ft->iHour == 0 && *p != '0'))
01069     {
01070         return false;
01071     }
01072     while (*p && *p != ':') p++;
01073     if (*p == ':') p++;
01074     while (*p == ' ') p++;
01075 
01076     // Minutes
01077     //
01078     ft->iMinute = (unsigned short)mux_atol(p);
01079     if (ft->iMinute > 59 || (ft->iMinute == 0 && *p != '0'))
01080     {
01081         return false;
01082     }
01083     while (*p && *p != ':') p++;
01084     if (*p == ':') p++;
01085     while (*p == ' ') p++;
01086 
01087     // Seconds
01088     //
01089     ft->iSecond = (unsigned short)mux_atol(p);
01090     if (ft->iSecond > 59 || (ft->iSecond == 0 && *p != '0'))
01091     {
01092         return false;
01093     }
01094     while (mux_isdigit(*p))
01095     {
01096         p++;
01097     }
01098 
01099     // Milliseconds, Microseconds, and Nanoseconds
01100     //
01101     if (*p == '.')
01102     {
01103         p++;
01104         size_t n;
01105         const char *q = strchr(p, ' ');
01106         if (q)
01107         {
01108             n = q - p;
01109         }
01110         else
01111         {
01112             n = strlen(p);
01113         }
01114 
01115         ParseDecimalSeconds(n, p, &ft->iMillisecond, &ft->iMicrosecond,
01116             &ft->iNanosecond);
01117     }
01118     while (*p && *p != ' ') p++;
01119     while (*p == ' ') p++;
01120 
01121     // Year
01122     //
01123     ft->iYear = (short)mux_atol(p);
01124     while (mux_isdigit(*p))
01125     {
01126         p++;
01127     }
01128     while (*p == ' ') p++;
01129     if (*p != '\0')
01130     {
01131         return false;
01132     }
01133 
01134     // DayOfYear and DayOfWeek
01135     //
01136     ft->iDayOfYear = 0;
01137     ft->iDayOfWeek = 0;
01138 
01139     return isValidDate(ft->iYear, ft->iMonth, ft->iDayOfMonth);
01140 }
01141 
01142 CLinearTimeDelta::CLinearTimeDelta(CLinearTimeAbsolute t0, CLinearTimeAbsolute t1)
01143 {
01144     m_tDelta = t1.m_tAbsolute - t0.m_tAbsolute;
01145 }
01146 
01147 long CLinearTimeDelta::ReturnDays(void)
01148 {
01149     return (long)(m_tDelta/FACTOR_100NS_PER_DAY);
01150 }
01151 
01152 long CLinearTimeDelta::ReturnSeconds(void)
01153 {
01154     return (long)(m_tDelta/FACTOR_100NS_PER_SECOND);
01155 }
01156 
01157 bool CLinearTimeAbsolute::ReturnFields(FIELDEDTIME *arg_tStruct)
01158 {
01159     return LinearTimeToFieldedTime(m_tAbsolute, arg_tStruct);
01160 }
01161 
01162 bool CLinearTimeAbsolute::SetString(const char *arg_tBuffer)
01163 {
01164     FIELDEDTIME ft;
01165     if (do_convtime(arg_tBuffer, &ft))
01166     {
01167         if (FieldedTimeToLinearTime(&ft, &m_tAbsolute))
01168         {
01169             return true;
01170         }
01171     }
01172     m_tAbsolute = 0;
01173     return false;
01174 }
01175 
01176 void CLinearTimeDelta::operator+=(const CLinearTimeDelta& ltd)
01177 {
01178     m_tDelta += ltd.m_tDelta;
01179 }
01180 
01181 CLinearTimeDelta operator-(const CLinearTimeAbsolute& ltaA, const CLinearTimeAbsolute& ltaB)
01182 {
01183     CLinearTimeDelta ltd;
01184     ltd.m_tDelta = ltaA.m_tAbsolute - ltaB.m_tAbsolute;
01185     return ltd;
01186 }
01187 
01188 CLinearTimeDelta operator-(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb)
01189 {
01190     CLinearTimeDelta ltd;
01191     ltd.m_tDelta = lta.m_tDelta - ltb.m_tDelta;
01192     return ltd;
01193 }
01194 
01195 CLinearTimeAbsolute operator+(const CLinearTimeAbsolute& ltaA, const CLinearTimeDelta& ltdB)
01196 {
01197     CLinearTimeAbsolute lta;
01198     lta.m_tAbsolute = ltaA.m_tAbsolute + ltdB.m_tDelta;
01199     return lta;
01200 }
01201 
01202 void CLinearTimeAbsolute::operator=(const CLinearTimeAbsolute& lta)
01203 {
01204     m_tAbsolute = lta.m_tAbsolute;
01205 }
01206 
01207 CLinearTimeDelta operator*(const CLinearTimeDelta& ltd, int Scale)
01208 {
01209     CLinearTimeDelta ltdResult;
01210     ltdResult.m_tDelta = ltd.m_tDelta * Scale;
01211     return ltdResult;
01212 }
01213 
01214 int operator/(const CLinearTimeDelta& ltdA, const CLinearTimeDelta& ltdB)
01215 {
01216     int iResult = (int)(ltdA.m_tDelta / ltdB.m_tDelta);
01217     return iResult;
01218 }
01219 
01220 bool operator<(const CLinearTimeDelta& ltdA, const CLinearTimeDelta& ltdB)
01221 {
01222     return ltdA.m_tDelta < ltdB.m_tDelta;
01223 }
01224 
01225 bool operator>(const CLinearTimeDelta& ltdA, const CLinearTimeDelta& ltdB)
01226 {
01227     return ltdA.m_tDelta > ltdB.m_tDelta;
01228 }
01229 
01230 void CLinearTimeAbsolute::operator-=(const CLinearTimeDelta& ltd)
01231 {
01232     m_tAbsolute -= ltd.m_tDelta;
01233 }
01234 
01235 void CLinearTimeAbsolute::operator+=(const CLinearTimeDelta& ltd)
01236 {
01237     m_tAbsolute += ltd.m_tDelta;
01238 }
01239 
01240 bool CLinearTimeAbsolute::SetFields(FIELDEDTIME *arg_tStruct)
01241 {
01242     m_tAbsolute = 0;
01243     return FieldedTimeToLinearTime(arg_tStruct, &m_tAbsolute);
01244 }
01245 
01246 static void SetStructTm(FIELDEDTIME *ft, struct tm *ptm)
01247 {
01248     ft->iYear = ptm->tm_year + 1900;
01249     ft->iMonth = ptm->tm_mon + 1;
01250     ft->iDayOfMonth = ptm->tm_mday;
01251     ft->iDayOfWeek = ptm->tm_wday;
01252     ft->iDayOfYear = 0;
01253     ft->iHour = ptm->tm_hour;
01254     ft->iMinute = ptm->tm_min;
01255     ft->iSecond = ptm->tm_sec;
01256 }
01257 
01258 void CLinearTimeAbsolute::ReturnUniqueString(char *buffer)
01259 {
01260     FIELDEDTIME ft;
01261     if (LinearTimeToFieldedTime(m_tAbsolute, &ft))
01262     {
01263         sprintf(buffer, "%04d%02d%02d-%02d%02d%02d", ft.iYear, ft.iMonth,
01264                 ft.iDayOfMonth, ft.iHour, ft.iMinute, ft.iSecond);
01265     }
01266     else
01267     {
01268         sprintf(buffer, "%03d", m_nCount++);
01269     }
01270 }
01271 
01272 char *CLinearTimeAbsolute::ReturnDateString(int nFracDigits)
01273 {
01274     FIELDEDTIME ft;
01275     if (LinearTimeToFieldedTime(m_tAbsolute, &ft))
01276     {
01277         // Sanitize Precision Request.
01278         //
01279         const int maxFracDigits = 7;
01280         const int minFracDigits = 0;
01281         if (nFracDigits < minFracDigits)
01282         {
01283             nFracDigits = minFracDigits;
01284         }
01285         else if (maxFracDigits < nFracDigits)
01286         {
01287             nFracDigits = maxFracDigits;
01288         }
01289 
01290         char buffer[11];
01291         buffer[0] = '\0';
01292         if (  0 < nFracDigits
01293            && (  ft.iMillisecond != 0
01294               || ft.iMicrosecond != 0
01295               || ft.iNanosecond != 0))
01296         {
01297             sprintf(buffer, ".%03d%03d%03d", ft.iMillisecond, ft.iMicrosecond,
01298                 ft.iNanosecond);
01299 
01300             // Remove trailing zeros.
01301             //
01302             char *p = (buffer + 1) + (nFracDigits - 1);
01303             while (*p == '0')
01304             {
01305                 p--;
01306             }
01307             p++;
01308             *p = '\0';
01309         }
01310         sprintf(m_Buffer, "%s %s %02d %02d:%02d:%02d%s %04d",
01311             DayOfWeekString[ft.iDayOfWeek], monthtab[ft.iMonth-1],
01312             ft.iDayOfMonth, ft.iHour, ft.iMinute, ft.iSecond, buffer,
01313             ft.iYear);
01314     }
01315     else
01316     {
01317         m_Buffer[0] = '\0';
01318     }
01319     return m_Buffer;
01320 }
01321 
01322 void CLinearTimeAbsolute::GetUTC(void)
01323 {
01324     GetUTCLinearTime(&m_tAbsolute);
01325 }
01326 
01327 void CLinearTimeAbsolute::GetLocal(void)
01328 {
01329     GetUTCLinearTime(&m_tAbsolute);
01330     UTC2Local();
01331 }
01332 
01333 bool FieldedTimeToLinearTime(FIELDEDTIME *ft, INT64 *plt)
01334 {
01335     if (!isValidDate(ft->iYear, ft->iMonth, ft->iDayOfMonth))
01336     {
01337         *plt = 0;
01338         return false;
01339     }
01340 
01341     int iFixedDay = FixedFromGregorian_Adjusted(ft->iYear, ft->iMonth, ft->iDayOfMonth);
01342     ft->iDayOfWeek = iMod(iFixedDay+1, 7);
01343 
01344     INT64 lt;
01345     lt  = iFixedDay * FACTOR_100NS_PER_DAY;
01346     lt += ft->iHour * FACTOR_100NS_PER_HOUR;
01347     lt += ft->iMinute * FACTOR_100NS_PER_MINUTE;
01348     lt += ft->iSecond * FACTOR_100NS_PER_SECOND;
01349     lt += ft->iMicrosecond * FACTOR_100NS_PER_MICROSECOND;
01350     lt += ft->iMillisecond * FACTOR_100NS_PER_MILLISECOND;
01351     lt += ft->