home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tcltk805.zip / tcl805s.zip / tcl8.0.5 / os2 / tclOS2Time.c < prev    next >
C/C++ Source or Header  |  2001-02-09  |  9KB  |  386 lines

  1. /* 
  2.  * tclOS2Time.c --
  3.  *
  4.  *    Contains OS/2 specific versions of Tcl functions that
  5.  *    obtain time values from the operating system.
  6.  *
  7.  * Copyright 1995 by Sun Microsystems, Inc.
  8.  * Copyright 1996-2001 Illya Vaes
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  */
  14.  
  15. #include "tclOS2Int.h"
  16.  
  17. #define SECSPERDAY (60L * 60L * 24L)
  18. #define SECSPERYEAR (SECSPERDAY * 365L)
  19. #define SECSPER4YEAR (SECSPERYEAR * 4L + SECSPERDAY)
  20.  
  21. /*
  22.  * The following arrays contain the day of year for the last day of
  23.  * each month, where index 1 is January.
  24.  */
  25.  
  26. static int normalDays[] = {
  27.     -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
  28. };
  29.  
  30. static int leapDays[] = {
  31.     -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
  32. };
  33.  
  34. /*
  35.  * Declarations for functions defined later in this file.
  36.  */
  37.  
  38. static struct tm *      ComputeGMT _ANSI_ARGS_((const time_t *tp));
  39.  
  40. /*
  41.  *----------------------------------------------------------------------
  42.  *
  43.  * TclpGetSeconds --
  44.  *
  45.  *    This procedure returns the number of seconds from the epoch.
  46.  *    On most Unix systems the epoch is Midnight Jan 1, 1970 GMT.
  47.  *      This goes for OS/2 with EMX too.
  48.  *
  49.  * Results:
  50.  *    Number of seconds from the epoch.
  51.  *
  52.  * Side effects:
  53.  *    None.
  54.  *
  55.  *----------------------------------------------------------------------
  56.  */
  57.  
  58. unsigned long
  59. TclpGetSeconds()
  60. {
  61.     return (unsigned long) time((time_t *) NULL);
  62. }
  63.  
  64. /*
  65.  *----------------------------------------------------------------------
  66.  *
  67.  * TclpGetClicks --
  68.  *
  69.  *    This procedure returns a value that represents the highest
  70.  *    resolution clock available on the system.  There are no
  71.  *    guarantees on what the resolution will be.  In Tcl we will
  72.  *    call this value a "click".  The start time is also system
  73.  *    dependant.
  74.  *
  75.  * Results:
  76.  *    Number of clicks from some start time.
  77.  *
  78.  * Side effects:
  79.  *    None.
  80.  *
  81.  *----------------------------------------------------------------------
  82.  */
  83.  
  84. unsigned long
  85. TclpGetClicks()
  86. {
  87. /*
  88. #ifndef CLI_VERSION
  89.     return WinGetCurrentTime(TclOS2GetHAB());
  90. #else
  91. */
  92.     QWORD timer;
  93.     DosTmrQueryTime(&timer);
  94.     return timer.ulLo;
  95. /*
  96. #endif
  97. */
  98. }
  99.  
  100. /*
  101.  *----------------------------------------------------------------------
  102.  *
  103.  * TclpGetTimeZone --
  104.  *
  105.  *    Determines the current timezone.  The method varies wildly
  106.  *    between different Platform implementations, so its hidden in
  107.  *    this function.
  108.  *
  109.  * Results:
  110.  *    Minutes wast of GMT.
  111.  *
  112.  * Side effects:
  113.  *    None.
  114.  *
  115.  *----------------------------------------------------------------------
  116.  */
  117.  
  118. int
  119. TclpGetTimeZone (currentTime)
  120.     unsigned long  currentTime;
  121. {
  122.     int timeZone;
  123.  
  124.     tzset();
  125.     /* EMX has "timezone" variable with seconds *west* of Greenwich */
  126.     /* include <time.h> */
  127.     timeZone = timezone / 60;
  128.  
  129.     return timeZone;
  130. }
  131.  
  132. /*
  133.  *----------------------------------------------------------------------
  134.  *
  135.  * TclpGetTime --
  136.  *
  137.  *    Gets the current system time in seconds and microseconds
  138.  *    since the beginning of the epoch: 00:00 UCT, January 1, 1970.
  139.  *
  140.  * Results:
  141.  *    Returns the current time in timePtr.
  142.  *
  143.  * Side effects:
  144.  *    None.
  145.  *
  146.  *----------------------------------------------------------------------
  147.  */
  148.  
  149. void
  150. TclpGetTime(timePtr)
  151.     Tcl_Time *timePtr;        /* Location to store time information. */
  152. {
  153.     struct timeb t;
  154.  
  155.     ftime(&t);
  156.     timePtr->sec = t.time;
  157.     timePtr->usec = t.millitm * 1000;
  158. }
  159.  
  160. /*
  161.  *----------------------------------------------------------------------
  162.  *
  163.  * TclpGetTZName --
  164.  *
  165.  *      Gets the current timezone string.
  166.  *
  167.  * Results:
  168.  *      Returns a pointer to a static string, or NULL on failure.
  169.  *
  170.  * Side effects:
  171.  *      None.
  172.  *
  173.  *----------------------------------------------------------------------
  174.  */
  175.  
  176. char *
  177. TclpGetTZName()
  178. {
  179.     tzset();
  180.     if (daylight && tzname[1] != NULL) {
  181.         return tzname[1];
  182.     } else {
  183.         return tzname[0];
  184.     }
  185. }
  186.  
  187. /*
  188.  *----------------------------------------------------------------------
  189.  *
  190.  * TclpGetDate --
  191.  *
  192.  *      This function converts between seconds and struct tm.  If
  193.  *      useGMT is true, then the returned date will be in Greenwich
  194.  *      Mean Time (GMT).  Otherwise, it will be in the local time zone.
  195.  *
  196.  * Results:
  197.  *      Returns a static tm structure.
  198.  *
  199.  * Side effects:
  200.  *      None.
  201.  *
  202.  *----------------------------------------------------------------------
  203.  */
  204.  
  205. struct tm *
  206. TclpGetDate(tp, useGMT)
  207.     const time_t *tp;
  208.     int useGMT;
  209. {
  210.     struct tm *tmPtr;
  211.     long time;
  212.  
  213.     if (!useGMT) {
  214.         tzset();
  215.  
  216.         /*
  217.          * If we are in the valid range, let the C run-time library
  218.          * handle it.  Otherwise we need to fake it.  Note that this
  219.          * algorithm ignores daylight savings time before the epoch.
  220.          */
  221.  
  222.         time = *tp - timezone;
  223.         if (time >= 0) {
  224.             return localtime(tp);
  225.         }
  226.  
  227.         /*
  228.          * If we aren't near to overflowing the long, just add the bias and
  229.          * use the normal calculation.  Otherwise we will need to adjust
  230.          * the result at the end.
  231.          */
  232.  
  233.         if (*tp < (LONG_MAX - 2 * SECSPERDAY)
  234.                 && *tp > (LONG_MIN + 2 * SECSPERDAY)) {
  235.             tmPtr = ComputeGMT(&time);
  236.         } else {
  237.             tmPtr = ComputeGMT(tp);
  238.  
  239.             tzset();
  240.  
  241.             /*
  242.              * Add the bias directly to the tm structure to avoid overflow.
  243.              * Propagate seconds overflow into minutes, hours and days.
  244.              */
  245.  
  246.             time = tmPtr->tm_sec - _timezone;
  247.             tmPtr->tm_sec = (int)(time % 60);
  248.             if (tmPtr->tm_sec < 0) {
  249.                 tmPtr->tm_sec += 60;
  250.                 time -= 60;
  251.             }
  252.  
  253.             time = tmPtr->tm_min + time/60;
  254.             tmPtr->tm_min = (int)(time % 60);
  255.             if (tmPtr->tm_min < 0) {
  256.                 tmPtr->tm_min += 60;
  257.                 time -= 60;
  258.             }
  259.  
  260.             time = tmPtr->tm_hour + time/60;
  261.             tmPtr->tm_hour = (int)(time % 24);
  262.             if (tmPtr->tm_hour < 0) {
  263.                 tmPtr->tm_hour += 24;
  264.                 time -= 24;
  265.             }
  266.  
  267.             time /= 24;
  268.             tmPtr->tm_mday += time;
  269.             tmPtr->tm_yday += time;
  270.             tmPtr->tm_wday = (tmPtr->tm_wday + time) % 7;
  271.         }
  272.     } else {
  273.         tmPtr = ComputeGMT(tp);
  274.     }
  275.     return tmPtr;
  276. }
  277.  
  278. /*
  279.  *----------------------------------------------------------------------
  280.  *
  281.  * ComputeGMT --
  282.  *
  283.  *      This function computes GMT given the number of seconds since
  284.  *      the epoch (midnight Jan 1 1970).
  285.  *
  286.  * Results:
  287.  *      Returns a statically allocated struct tm.
  288.  *
  289.  * Side effects:
  290.  *      Updates the values of the static struct tm.
  291.  *
  292.  *----------------------------------------------------------------------
  293.  */
  294.  
  295. static struct tm *
  296. ComputeGMT(tp)
  297.     const time_t *tp;
  298. {
  299.     static struct tm tm;          /* This should be allocated per thread.*/
  300.     long tmp, rem;
  301.     int isLeap;
  302.     int *days;
  303.  
  304.     /*
  305.      * Compute the 4 year span containing the specified time.
  306.      */
  307.  
  308.     tmp = *tp / SECSPER4YEAR;
  309.     rem = *tp % SECSPER4YEAR;
  310.  
  311.     /*
  312.      * Correct for weird mod semantics so the remainder is always positive.
  313.      */
  314.  
  315.     if (rem < 0) {
  316.         tmp--;
  317.         rem += SECSPER4YEAR;
  318.     }
  319.  
  320.     /*
  321.      * Compute the year after 1900 by taking the 4 year span and adjusting
  322.      * for the remainder.  This works because 2000 is a leap year, and
  323.      * 1900/2100 are out of the range.
  324.      */
  325.  
  326.     tmp = (tmp * 4) + 70;
  327.     isLeap = 0;
  328.     if (rem >= SECSPERYEAR) {                     /* 1971, etc. */
  329.         tmp++;
  330.         rem -= SECSPERYEAR;
  331.         if (rem >= SECSPERYEAR) {                  /* 1972, etc. */
  332.             tmp++;
  333.             rem -= SECSPERYEAR;
  334.             if (rem >= SECSPERYEAR + SECSPERDAY) { /* 1973, etc. */
  335.                 tmp++;
  336.                 rem -= SECSPERYEAR + SECSPERDAY;
  337.             } else {
  338.                 isLeap = 1;
  339.             }
  340.         }
  341.     }
  342.     tm.tm_year = tmp;
  343.  
  344.     /*
  345.      * Compute the day of year and leave the seconds in the current day in
  346.      * the remainder.
  347.      */
  348.  
  349.     tm.tm_yday = rem / SECSPERDAY;
  350.     rem %= SECSPERDAY;
  351.  
  352.     /*
  353.      * Compute the time of day.
  354.      */
  355.  
  356.     tm.tm_hour = rem / 3600;
  357.     rem %= 3600;
  358.     tm.tm_min = rem / 60;
  359.     tm.tm_sec = rem % 60;
  360.  
  361.     /*
  362.      * Compute the month and day of month.
  363.      */
  364.  
  365.     days = (isLeap) ? leapDays : normalDays;
  366.     for (tmp = 1; days[tmp] < tm.tm_yday; tmp++) {
  367.     }
  368.     tm.tm_mon = --tmp;
  369.     tm.tm_mday = tm.tm_yday - days[tmp];
  370.  
  371.     /*
  372.      * Compute day of week.  Epoch started on a Thursday.
  373.      */
  374.  
  375.     tm.tm_wday = (*tp / SECSPERDAY) + 4;
  376.     if ((*tp % SECSPERDAY) < 0) {
  377.         tm.tm_wday--;
  378.     }
  379.     tm.tm_wday %= 7;
  380.     if (tm.tm_wday < 0) {
  381.         tm.tm_wday += 7;
  382.     }
  383.  
  384.     return &tm;
  385. }
  386.