diff options
Diffstat (limited to 'unix/tclUnixTime.c')
-rw-r--r-- | unix/tclUnixTime.c | 425 |
1 files changed, 180 insertions, 245 deletions
diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c index c7921fe..707dfbc 100644 --- a/unix/tclUnixTime.c +++ b/unix/tclUnixTime.c @@ -11,11 +11,8 @@ */ #include "tclInt.h" +#include "tclPort.h" #include <locale.h> -#if defined(TCL_WIDE_CLICKS) && defined(MAC_OSX_TCL) -#include <mach/mach_time.h> -#endif - #define TM_YEAR_BASE 1900 #define IsLeapYear(x) (((x)%4 == 0) && ((x)%100 != 0 || (x)%400 == 0)) @@ -46,20 +43,8 @@ static char *lastTZ = NULL; /* Holds the last setting of the TZ * Static functions declared in this file. */ -static void SetTZIfNecessary(void); -static void CleanupMemory(ClientData clientData); -static void NativeScaleTime(Tcl_Time *timebuf, - ClientData clientData); -static void NativeGetTime(Tcl_Time *timebuf, - ClientData clientData); - -/* - * TIP #233 (Virtualized Time): Data for the time hooks, if any. - */ - -Tcl_GetTimeProc *tclGetTimeProcPtr = NativeGetTime; -Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime; -ClientData tclTimeClientData = NULL; +static void SetTZIfNecessary _ANSI_ARGS_((void)); +static void CleanupMemory _ANSI_ARGS_((ClientData)); /* *---------------------------------------------------------------------- @@ -79,9 +64,9 @@ ClientData tclTimeClientData = NULL; */ unsigned long -TclpGetSeconds(void) +TclpGetSeconds() { - return time(NULL); + return time((time_t *) NULL); } /* @@ -104,47 +89,37 @@ TclpGetSeconds(void) */ unsigned long -TclpGetClicks(void) +TclpGetClicks() { unsigned long now; #ifdef NO_GETTOD - if (tclGetTimeProcPtr != NativeGetTime) { - Tcl_Time time; - - tclGetTimeProcPtr(&time, tclTimeClientData); - now = time.sec*1000000 + time.usec; - } else { - /* - * A semi-NativeGetTime, specialized to clicks. - */ - struct tms dummy; - - now = (unsigned long) times(&dummy); - } + struct tms dummy; #else - Tcl_Time time; + struct timeval date; +#endif - tclGetTimeProcPtr(&time, tclTimeClientData); - now = time.sec*1000000 + time.usec; +#ifdef NO_GETTOD + now = (unsigned long) times(&dummy); +#else + gettimeofday(&date, NULL); + now = date.tv_sec*1000000 + date.tv_usec; #endif return now; } -#ifdef TCL_WIDE_CLICKS /* *---------------------------------------------------------------------- * - * TclpGetWideClicks -- + * TclpGetTimeZone -- * - * This procedure returns a WideInt value that represents the highest - * resolution clock available on the system. There are no garantees on - * what the resolution will be. In Tcl we will call this value a "click". - * The start time is also system dependant. + * Determines the current timezone. The method varies wildly between + * different platform implementations, so its hidden in this function. * * Results: - * Number of WideInt clicks from some start time. + * The return value is the local time zone, measured in minutes away from + * GMT (-ve for east, +ve for west). * * Side effects: * None. @@ -152,74 +127,103 @@ TclpGetClicks(void) *---------------------------------------------------------------------- */ -Tcl_WideInt -TclpGetWideClicks(void) +int +TclpGetTimeZone(currentTime) + Tcl_WideInt currentTime; { - Tcl_WideInt now; + int timeZone; - if (tclGetTimeProcPtr != NativeGetTime) { - Tcl_Time time; + /* + * We prefer first to use the time zone in "struct tm" if the structure + * contains such a member. Following that, we try to locate the external + * 'timezone' variable and use its value. If both of those methods fail, + * we attempt to convert a known time to local time and use the difference + * from UTC as the local time zone. In all cases, we need to undo any + * Daylight Saving Time adjustment. + */ - tclGetTimeProcPtr(&time, tclTimeClientData); - now = (Tcl_WideInt) (time.sec*1000000 + time.usec); - } else { -#ifdef MAC_OSX_TCL - now = (Tcl_WideInt) (mach_absolute_time() & INT64_MAX); -#else -#error Wide high-resolution clicks not implemented on this platform +#if defined(HAVE_TM_TZADJ) +#define TCL_GOT_TIMEZONE + /* + * Struct tm contains tm_tzadj - that value may be used. + */ + + time_t curTime = (time_t) currentTime; + struct tm *timeDataPtr = TclpLocaltime((TclpTime_t) &curTime); + + timeZone = timeDataPtr->tm_tzadj / 60; + if (timeDataPtr->tm_isdst) { + timeZone += 60; + } #endif + +#if defined(HAVE_TM_GMTOFF) && !defined (TCL_GOT_TIMEZONE) +#define TCL_GOT_TIMEZONE + /* + * Struct tm contains tm_gmtoff - that value may be used. + */ + + time_t curTime = (time_t) currentTime; + struct tm *timeDataPtr = TclpLocaltime((TclpTime_t) &curTime); + + timeZone = -(timeDataPtr->tm_gmtoff / 60); + if (timeDataPtr->tm_isdst) { + timeZone += 60; } +#endif - return now; -} - -/* - *---------------------------------------------------------------------- - * - * TclpWideClicksToNanoseconds -- - * - * This procedure converts click values from the TclpGetWideClicks native - * resolution to nanosecond resolution. - * - * Results: - * Number of nanoseconds from some start time. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ +#if defined(HAVE_TIMEZONE_VAR) && !defined(TCL_GOT_TIMEZONE) && !defined(USE_DELTA_FOR_TZ) +#define TCL_GOT_TIMEZONE + /* + * The 'timezone' external var is present and may be used. + */ -double -TclpWideClicksToNanoseconds( - Tcl_WideInt clicks) -{ - double nsec; + SetTZIfNecessary(); - if (tclGetTimeProcPtr != NativeGetTime) { - nsec = clicks * 1000; - } else { -#ifdef MAC_OSX_TCL - static mach_timebase_info_data_t tb; - static uint64_t maxClicksForUInt64; - - if (!tb.denom) { - mach_timebase_info(&tb); - maxClicksForUInt64 = UINT64_MAX / tb.numer; - } - if ((uint64_t) clicks < maxClicksForUInt64) { - nsec = ((uint64_t) clicks) * tb.numer / tb.denom; - } else { - nsec = ((long double) (uint64_t) clicks) * tb.numer / tb.denom; - } -#else -#error Wide high-resolution clicks not implemented on this platform + /* + * Note: this is not a typo in "timezone" below! See tzset documentation + * for details. + */ + + timeZone = timezone / 60; #endif + +#if !defined(TCL_GOT_TIMEZONE) +#define TCL_GOT_TIMEZONE + /* + * Fallback - determine time zone with a known reference time. + */ + + time_t tt; + struct tm *stm; + + tt = 849268800L; /* 1996-11-29 12:00:00 GMT */ + stm = TclpLocaltime((TclpTime_t) &tt); /* eg 1996-11-29 6:00:00 CST6CDT */ + + /* + * The calculation below assumes a max of +12 or -12 hours from GMT. + */ + + timeZone = (12 - stm->tm_hour)*60 + (0 - stm->tm_min); + if (stm->tm_isdst) { + timeZone += 60; } - return nsec; + /* + * Now have offset for our known reference time, eg +360 for CST6CDT. + */ +#endif + +#ifndef TCL_GOT_TIMEZONE + /* + * Cause fatal compile error, we don't know how to get timezone. + */ + +#error autoconf did not figure out how to determine the timezone. +#endif + + return timeZone; } -#endif /* TCL_WIDE_CLICKS */ /* *---------------------------------------------------------------------- @@ -229,9 +233,6 @@ TclpWideClicksToNanoseconds( * Gets the current system time in seconds and microseconds since the * beginning of the epoch: 00:00 UCT, January 1, 1970. * - * This function is hooked, allowing users to specify their own virtual - * system time. - * * Results: * Returns the current time in timePtr. * @@ -242,10 +243,14 @@ TclpWideClicksToNanoseconds( */ void -Tcl_GetTime( - Tcl_Time *timePtr) /* Location to store time information. */ +Tcl_GetTime(timePtr) + Tcl_Time *timePtr; /* Location to store time information. */ { - tclGetTimeProcPtr(timePtr, tclTimeClientData); + struct timeval tv; + + (void) gettimeofday(&tv, NULL); + timePtr->sec = tv.tv_sec; + timePtr->usec = tv.tv_usec; } /* @@ -267,9 +272,9 @@ Tcl_GetTime( */ struct tm * -TclpGetDate( - const time_t *time, - int useGMT) +TclpGetDate(time, useGMT) + TclpTime_t time; + int useGMT; { if (useGMT) { return TclpGmtime(time); @@ -281,9 +286,48 @@ TclpGetDate( /* *---------------------------------------------------------------------- * + * TclpStrftime -- + * + * On Unix, we can safely call the native strftime implementation, + * and also ignore the useGMT parameter. + * + * Results: + * The normal strftime result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +size_t +TclpStrftime(s, maxsize, format, t, useGMT) + char *s; + size_t maxsize; + CONST char *format; + CONST struct tm *t; + int useGMT; +{ + if (format[0] == '%' && format[1] == 'Q') { + /* Format as a stardate */ + sprintf(s, "Stardate %2d%03d.%01d", + (((t->tm_year + TM_YEAR_BASE) + 377) - 2323), + (((t->tm_yday + 1) * 1000) / + (365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))), + (((t->tm_hour * 60) + t->tm_min)/144)); + return(strlen(s)); + } + setlocale(LC_TIME, ""); + return strftime(s, maxsize, format, t); +} + +/* + *---------------------------------------------------------------------- + * * TclpGmtime -- * - * Wrapper around the 'gmtime' library function to make it thread safe. + * Wrapper around the 'gmtime' library function to make it thread + * safe. * * Results: * Returns a pointer to a 'struct tm' in thread-specific data. @@ -295,25 +339,28 @@ TclpGetDate( */ struct tm * -TclpGmtime( - const time_t *timePtr) /* Pointer to the number of seconds since the - * local system's epoch */ +TclpGmtime(tt) + TclpTime_t_CONST tt; { + CONST time_t *timePtr = (CONST time_t *) tt; + /* Pointer to the number of seconds + * since the local system's epoch */ + /* * Get a thread-local buffer to hold the returned time. */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tmKey); - #ifdef HAVE_GMTIME_R - gmtime_r(timePtr, &tsdPtr->gmtime_buf); + gmtime_r(timePtr, &(tsdPtr->gmtime_buf)); #else Tcl_MutexLock(&tmMutex); - memcpy(&tsdPtr->gmtime_buf, gmtime(timePtr), sizeof(struct tm)); + memcpy((VOID *) &(tsdPtr->gmtime_buf), + (VOID *) gmtime(timePtr), + sizeof(struct tm)); Tcl_MutexUnlock(&tmMutex); #endif - - return &tsdPtr->gmtime_buf; + return &(tsdPtr->gmtime_buf); } /* @@ -334,145 +381,33 @@ TclpGmtime( */ struct tm * -TclpLocaltime( - const time_t *timePtr) /* Pointer to the number of seconds since the - * local system's epoch */ +TclpLocaltime(tt) + TclpTime_t_CONST tt; { + CONST time_t *timePtr = (CONST time_t *) tt; + /* Pointer to the number of seconds + * since the local system's epoch */ /* * Get a thread-local buffer to hold the returned time. */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tmKey); - SetTZIfNecessary(); #ifdef HAVE_LOCALTIME_R - localtime_r(timePtr, &tsdPtr->localtime_buf); + localtime_r(timePtr, &(tsdPtr->localtime_buf)); #else Tcl_MutexLock(&tmMutex); - memcpy(&tsdPtr->localtime_buf, localtime(timePtr), sizeof(struct tm)); + memcpy((VOID *) &(tsdPtr -> localtime_buf), + (VOID *) localtime(timePtr), + sizeof(struct tm)); Tcl_MutexUnlock(&tmMutex); #endif - - return &tsdPtr->localtime_buf; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_SetTimeProc -- - * - * TIP #233 (Virtualized Time): Registers two handlers for the - * virtualization of Tcl's access to time information. - * - * Results: - * None. - * - * Side effects: - * Remembers the handlers, alters core behaviour. - * - *---------------------------------------------------------------------- - */ - -void -Tcl_SetTimeProc( - Tcl_GetTimeProc *getProc, - Tcl_ScaleTimeProc *scaleProc, - ClientData clientData) -{ - tclGetTimeProcPtr = getProc; - tclScaleTimeProcPtr = scaleProc; - tclTimeClientData = clientData; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_QueryTimeProc -- - * - * TIP #233 (Virtualized Time): Query which time handlers are registered. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -Tcl_QueryTimeProc( - Tcl_GetTimeProc **getProc, - Tcl_ScaleTimeProc **scaleProc, - ClientData *clientData) -{ - if (getProc) { - *getProc = tclGetTimeProcPtr; - } - if (scaleProc) { - *scaleProc = tclScaleTimeProcPtr; - } - if (clientData) { - *clientData = tclTimeClientData; - } -} - -/* - *---------------------------------------------------------------------- - * - * NativeScaleTime -- - * - * TIP #233: Scale from virtual time to the real-time. For native scaling - * the relationship is 1:1 and nothing has to be done. - * - * Results: - * Scales the time in timePtr. - * - * Side effects: - * See above. - * - *---------------------------------------------------------------------- - */ - -static void -NativeScaleTime( - Tcl_Time *timePtr, - ClientData clientData) -{ - /* Native scale is 1:1. Nothing is done */ + return &(tsdPtr->localtime_buf); } /* *---------------------------------------------------------------------- * - * NativeGetTime -- - * - * TIP #233: 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. - * - *---------------------------------------------------------------------- - */ - -static void -NativeGetTime( - Tcl_Time *timePtr, - ClientData clientData) -{ - struct timeval tv; - - (void) gettimeofday(&tv, NULL); - timePtr->sec = tv.tv_sec; - timePtr->usec = tv.tv_usec; -} -/* - *---------------------------------------------------------------------- - * * SetTZIfNecessary -- * * Determines whether a call to 'tzset' is needed prior to the next call @@ -490,9 +425,9 @@ NativeGetTime( */ static void -SetTZIfNecessary(void) +SetTZIfNecessary() { - const char *newTZ = getenv("TZ"); + CONST char *newTZ = getenv("TZ"); Tcl_MutexLock(&tmMutex); if (newTZ == NULL) { @@ -501,7 +436,7 @@ SetTZIfNecessary(void) if (lastTZ == NULL || strcmp(lastTZ, newTZ)) { tzset(); if (lastTZ == NULL) { - Tcl_CreateExitHandler(CleanupMemory, NULL); + Tcl_CreateExitHandler(CleanupMemory, (ClientData) NULL); } else { Tcl_Free(lastTZ); } @@ -529,8 +464,8 @@ SetTZIfNecessary(void) */ static void -CleanupMemory( - ClientData ignored) +CleanupMemory(ignored) + ClientData ignored; { ckfree(lastTZ); } |