374 lines
7.8 KiB
C
374 lines
7.8 KiB
C
|
/*
|
|||
|
* tclWinTime.c --
|
|||
|
*
|
|||
|
* Contains Windows specific versions of Tcl functions that
|
|||
|
* obtain time values from the operating system.
|
|||
|
*
|
|||
|
* Copyright 1995 by Sun Microsystems, Inc.
|
|||
|
*
|
|||
|
* See the file "license.terms" for information on usage and redistribution
|
|||
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|||
|
*
|
|||
|
* SCCS: @(#) tclWinTime.c 1.5 96/07/23 16:19:01
|
|||
|
*/
|
|||
|
|
|||
|
#include "tclInt.h"
|
|||
|
#include "tclPort.h"
|
|||
|
|
|||
|
#define SECSPERDAY (60L * 60L * 24L)
|
|||
|
#define SECSPERYEAR (SECSPERDAY * 365L)
|
|||
|
#define SECSPER4YEAR (SECSPERYEAR * 4L + SECSPERDAY)
|
|||
|
|
|||
|
/*
|
|||
|
* The following arrays contain the day of year for the last day of
|
|||
|
* each month, where index 1 is January.
|
|||
|
*/
|
|||
|
|
|||
|
static int normalDays[] = {
|
|||
|
-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
|
|||
|
};
|
|||
|
|
|||
|
static int leapDays[] = {
|
|||
|
-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
|
|||
|
};
|
|||
|
|
|||
|
/*
|
|||
|
* Declarations for functions defined later in this file.
|
|||
|
*/
|
|||
|
|
|||
|
static struct tm * ComputeGMT _ANSI_ARGS_((const time_t *tp));
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclpGetSeconds --
|
|||
|
*
|
|||
|
* This procedure returns the number of seconds from the epoch.
|
|||
|
* On most Unix systems the epoch is Midnight Jan 1, 1970 GMT.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* Number of seconds from the epoch.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
unsigned long
|
|||
|
TclpGetSeconds()
|
|||
|
{
|
|||
|
return (unsigned long) time((time_t *) NULL);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclpGetClicks --
|
|||
|
*
|
|||
|
* This procedure returns a value that represents the highest
|
|||
|
* resolution clock available on the system. There are no
|
|||
|
* guarantees on what the resolution will be. In Tcl we will
|
|||
|
* call this value a "click". The start time is also system
|
|||
|
* dependant.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* Number of clicks from some start time.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
unsigned long
|
|||
|
TclpGetClicks()
|
|||
|
{
|
|||
|
return GetTickCount();
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclpGetTimeZone --
|
|||
|
*
|
|||
|
* Determines the current timezone. The method varies wildly
|
|||
|
* between different Platform implementations, so its hidden in
|
|||
|
* this function.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* Minutes west of GMT.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
int
|
|||
|
TclpGetTimeZone (currentTime)
|
|||
|
unsigned long currentTime;
|
|||
|
{
|
|||
|
int timeZone;
|
|||
|
|
|||
|
tzset();
|
|||
|
timeZone = _timezone / 60;
|
|||
|
|
|||
|
return timeZone;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclpGetTime --
|
|||
|
*
|
|||
|
* Gets the current system time in seconds and microseconds
|
|||
|
* since the beginning of the epoch: 00:00 UCT, January 1, 1970.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* Returns the current time in timePtr.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
void
|
|||
|
TclpGetTime(timePtr)
|
|||
|
Tcl_Time *timePtr; /* Location to store time information. */
|
|||
|
{
|
|||
|
struct timeb t;
|
|||
|
|
|||
|
ftime(&t);
|
|||
|
timePtr->sec = t.time;
|
|||
|
timePtr->usec = t.millitm * 1000;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclpGetTZName --
|
|||
|
*
|
|||
|
* Gets the current timezone string.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* Returns a pointer to a static string, or NULL on failure.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
char *
|
|||
|
TclpGetTZName()
|
|||
|
{
|
|||
|
tzset();
|
|||
|
if (_daylight && _tzname[1] != NULL) {
|
|||
|
return _tzname[1];
|
|||
|
} else {
|
|||
|
return _tzname[0];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclpGetDate --
|
|||
|
*
|
|||
|
* This function converts between seconds and struct tm. If
|
|||
|
* useGMT is true, then the returned date will be in Greenwich
|
|||
|
* Mean Time (GMT). Otherwise, it will be in the local time zone.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* Returns a static tm structure.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
struct tm *
|
|||
|
TclpGetDate(tp, useGMT)
|
|||
|
const time_t *tp;
|
|||
|
int useGMT;
|
|||
|
{
|
|||
|
struct tm *tmPtr;
|
|||
|
long time;
|
|||
|
|
|||
|
if (!useGMT) {
|
|||
|
tzset();
|
|||
|
|
|||
|
/*
|
|||
|
* If we are in the valid range, let the C run-time library
|
|||
|
* handle it. Otherwise we need to fake it. Note that this
|
|||
|
* algorithm ignores daylight savings time before the epoch.
|
|||
|
*/
|
|||
|
|
|||
|
time = *tp - _timezone;
|
|||
|
if (time >= 0) {
|
|||
|
return localtime(tp);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* If we aren't near to overflowing the long, just add the bias and
|
|||
|
* use the normal calculation. Otherwise we will need to adjust
|
|||
|
* the result at the end.
|
|||
|
*/
|
|||
|
|
|||
|
if (*tp < (LONG_MAX - 2 * SECSPERDAY)
|
|||
|
&& *tp > (LONG_MIN + 2 * SECSPERDAY)) {
|
|||
|
tmPtr = ComputeGMT(&time);
|
|||
|
} else {
|
|||
|
tmPtr = ComputeGMT(tp);
|
|||
|
|
|||
|
tzset();
|
|||
|
|
|||
|
/*
|
|||
|
* Add the bias directly to the tm structure to avoid overflow.
|
|||
|
* Propagate seconds overflow into minutes, hours and days.
|
|||
|
*/
|
|||
|
|
|||
|
time = tmPtr->tm_sec - _timezone;
|
|||
|
tmPtr->tm_sec = (int)(time % 60);
|
|||
|
if (tmPtr->tm_sec < 0) {
|
|||
|
tmPtr->tm_sec += 60;
|
|||
|
time -= 60;
|
|||
|
}
|
|||
|
|
|||
|
time = tmPtr->tm_min + time/60;
|
|||
|
tmPtr->tm_min = (int)(time % 60);
|
|||
|
if (tmPtr->tm_min < 0) {
|
|||
|
tmPtr->tm_min += 60;
|
|||
|
time -= 60;
|
|||
|
}
|
|||
|
|
|||
|
time = tmPtr->tm_hour + time/60;
|
|||
|
tmPtr->tm_hour = (int)(time % 24);
|
|||
|
if (tmPtr->tm_hour < 0) {
|
|||
|
tmPtr->tm_hour += 24;
|
|||
|
time -= 24;
|
|||
|
}
|
|||
|
|
|||
|
time /= 24;
|
|||
|
tmPtr->tm_mday += time;
|
|||
|
tmPtr->tm_yday += time;
|
|||
|
tmPtr->tm_wday = (tmPtr->tm_wday + time) % 7;
|
|||
|
}
|
|||
|
} else {
|
|||
|
tmPtr = ComputeGMT(tp);
|
|||
|
}
|
|||
|
return tmPtr;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* ComputeGMT --
|
|||
|
*
|
|||
|
* This function computes GMT given the number of seconds since
|
|||
|
* the epoch (midnight Jan 1 1970).
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* Returns a statically allocated struct tm.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* Updates the values of the static struct tm.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
static struct tm *
|
|||
|
ComputeGMT(tp)
|
|||
|
const time_t *tp;
|
|||
|
{
|
|||
|
static struct tm tm; /* This should be allocated per thread.*/
|
|||
|
long tmp, rem;
|
|||
|
int isLeap;
|
|||
|
int *days;
|
|||
|
|
|||
|
/*
|
|||
|
* Compute the 4 year span containing the specified time.
|
|||
|
*/
|
|||
|
|
|||
|
tmp = *tp / SECSPER4YEAR;
|
|||
|
rem = *tp % SECSPER4YEAR;
|
|||
|
|
|||
|
/*
|
|||
|
* Correct for weird mod semantics so the remainder is always positive.
|
|||
|
*/
|
|||
|
|
|||
|
if (rem < 0) {
|
|||
|
tmp--;
|
|||
|
rem += SECSPER4YEAR;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Compute the year after 1900 by taking the 4 year span and adjusting
|
|||
|
* for the remainder. This works because 2000 is a leap year, and
|
|||
|
* 1900/2100 are out of the range.
|
|||
|
*/
|
|||
|
|
|||
|
tmp = (tmp * 4) + 70;
|
|||
|
isLeap = 0;
|
|||
|
if (rem >= SECSPERYEAR) { /* 1971, etc. */
|
|||
|
tmp++;
|
|||
|
rem -= SECSPERYEAR;
|
|||
|
if (rem > SECSPERYEAR) { /* 1972, etc. */
|
|||
|
tmp++;
|
|||
|
rem -= SECSPERYEAR;
|
|||
|
if (rem > SECSPERYEAR + SECSPERDAY) { /* 1973, etc. */
|
|||
|
tmp++;
|
|||
|
rem -= SECSPERYEAR + SECSPERDAY;
|
|||
|
} else {
|
|||
|
isLeap = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
tm.tm_year = tmp;
|
|||
|
|
|||
|
/*
|
|||
|
* Compute the day of year and leave the seconds in the current day in
|
|||
|
* the remainder.
|
|||
|
*/
|
|||
|
|
|||
|
tm.tm_yday = rem / SECSPERDAY;
|
|||
|
rem %= SECSPERDAY;
|
|||
|
|
|||
|
/*
|
|||
|
* Compute the time of day.
|
|||
|
*/
|
|||
|
|
|||
|
tm.tm_hour = rem / 3600;
|
|||
|
rem %= 3600;
|
|||
|
tm.tm_min = rem / 60;
|
|||
|
tm.tm_sec = rem % 60;
|
|||
|
|
|||
|
/*
|
|||
|
* Compute the month and day of month.
|
|||
|
*/
|
|||
|
|
|||
|
days = (isLeap) ? leapDays : normalDays;
|
|||
|
for (tmp = 1; days[tmp] < tm.tm_yday; tmp++) {
|
|||
|
}
|
|||
|
tm.tm_mon = --tmp;
|
|||
|
tm.tm_mday = tm.tm_yday - days[tmp];
|
|||
|
|
|||
|
/*
|
|||
|
* Compute day of week. Epoch started on a Thursday.
|
|||
|
*/
|
|||
|
|
|||
|
tm.tm_wday = (*tp / SECSPERDAY) + 4;
|
|||
|
if ((*tp % SECSPERDAY) < 0) {
|
|||
|
tm.tm_wday--;
|
|||
|
}
|
|||
|
tm.tm_wday %= 7;
|
|||
|
if (tm.tm_wday < 0) {
|
|||
|
tm.tm_wday += 7;
|
|||
|
}
|
|||
|
|
|||
|
return &tm;
|
|||
|
}
|