diff options
Diffstat (limited to 'unix/tclUnixTime.c')
| -rw-r--r-- | unix/tclUnixTime.c | 283 |
1 files changed, 154 insertions, 129 deletions
diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c index c4f6737..b98f2e1 100644 --- a/unix/tclUnixTime.c +++ b/unix/tclUnixTime.c @@ -4,26 +4,29 @@ * Contains Unix specific versions of Tcl functions that obtain time * values from the operating system. * - * Copyright © 1995 Sun Microsystems, Inc. + * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.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)) + /* * TclpGetDate is coded to return a pointer to a 'struct tm'. For thread * safety, this structure must be in thread-specific data. The 'tmKey' * variable is the key to this buffer. */ -#ifndef TCL_NO_DEPRECATED static Tcl_ThreadDataKey tmKey; -typedef struct { +typedef struct ThreadSpecificData { struct tm gmtime_buf; struct tm localtime_buf; } ThreadSpecificData; @@ -44,13 +47,11 @@ static char *lastTZ = NULL; /* Holds the last setting of the TZ */ static void SetTZIfNecessary(void); -static void CleanupMemory(void *clientData); -#endif /* TCL_NO_DEPRECATED */ - +static void CleanupMemory(ClientData clientData); static void NativeScaleTime(Tcl_Time *timebuf, - void *clientData); + ClientData clientData); static void NativeGetTime(Tcl_Time *timebuf, - void *clientData); + ClientData clientData); /* * TIP #233 (Virtualized Time): Data for the time hooks, if any. @@ -58,24 +59,7 @@ static void NativeGetTime(Tcl_Time *timebuf, Tcl_GetTimeProc *tclGetTimeProcPtr = NativeGetTime; Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime; -void *tclTimeClientData = NULL; - -/* - * Inlined version of Tcl_GetTime. - */ - -static inline void -GetTime( - Tcl_Time *timePtr) -{ - tclGetTimeProcPtr(timePtr, tclTimeClientData); -} - -static inline int -IsTimeNative(void) -{ - return tclGetTimeProcPtr == NativeGetTime; -} +ClientData tclTimeClientData = NULL; /* *---------------------------------------------------------------------- @@ -103,38 +87,12 @@ TclpGetSeconds(void) /* *---------------------------------------------------------------------- * - * TclpGetMicroseconds -- - * - * This procedure returns the number of microseconds from the epoch. - * On most Unix systems the epoch is Midnight Jan 1, 1970 GMT. - * - * Results: - * Number of microseconds from the epoch. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -long long -TclpGetMicroseconds(void) -{ - Tcl_Time time; - - GetTime(&time); - return ((long long) time.sec)*1000000 + time.usec; -} - -/* - *---------------------------------------------------------------------- - * * TclpGetClicks -- * * This procedure returns a value that represents the highest resolution - * clock available on the system. There are no guarantees on what the + * 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 dependent. + * start time is also system dependant. * * Results: * Number of clicks from some start time. @@ -151,11 +109,11 @@ TclpGetClicks(void) unsigned long now; #ifdef NO_GETTOD - if (!IsTimeNative()) { + if (tclGetTimeProcPtr != NativeGetTime) { Tcl_Time time; - GetTime(&time); - now = ((unsigned long)(time.sec)*1000000UL) + (unsigned long)(time.usec); + (*tclGetTimeProcPtr) (&time, tclTimeClientData); + now = time.sec*1000000 + time.usec; } else { /* * A semi-NativeGetTime, specialized to clicks. @@ -164,26 +122,26 @@ TclpGetClicks(void) now = (unsigned long) times(&dummy); } -#else /* !NO_GETTOD */ +#else Tcl_Time time; - GetTime(&time); - now = ((unsigned long)(time.sec)*1000000UL) + (unsigned long)(time.usec); -#endif /* NO_GETTOD */ + (*tclGetTimeProcPtr) (&time, tclTimeClientData); + now = time.sec*1000000 + time.usec; +#endif return now; } #ifdef TCL_WIDE_CLICKS /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * TclpGetWideClicks -- * * This procedure returns a WideInt value that represents the highest - * resolution clock available on the system. There are no guarantees on + * 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 dependent. + * The start time is also system dependant. * * Results: * Number of WideInt clicks from some start time. @@ -191,32 +149,32 @@ TclpGetClicks(void) * Side effects: * None. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -long long +Tcl_WideInt TclpGetWideClicks(void) { - long long now; + Tcl_WideInt now; - if (!IsTimeNative()) { + if (tclGetTimeProcPtr != NativeGetTime) { Tcl_Time time; - GetTime(&time); - now = ((long long) time.sec)*1000000 + time.usec; + (*tclGetTimeProcPtr) (&time, tclTimeClientData); + now = (Tcl_WideInt) (time.sec*1000000 + time.usec); } else { #ifdef MAC_OSX_TCL - now = (long long) (mach_absolute_time() & INT64_MAX); + now = (Tcl_WideInt) (mach_absolute_time() & INT64_MAX); #else #error Wide high-resolution clicks not implemented on this platform -#endif /* MAC_OSX_TCL */ +#endif } return now; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * TclpWideClicksToNanoseconds -- * @@ -229,22 +187,22 @@ TclpGetWideClicks(void) * Side effects: * None. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ double TclpWideClicksToNanoseconds( - long long clicks) + Tcl_WideInt clicks) { double nsec; - if (!IsTimeNative()) { + 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; @@ -256,23 +214,24 @@ TclpWideClicksToNanoseconds( } #else #error Wide high-resolution clicks not implemented on this platform -#endif /* MAC_OSX_TCL */ +#endif } return nsec; } +#endif /* TCL_WIDE_CLICKS */ /* *---------------------------------------------------------------------- * - * TclpWideClickInMicrosec -- + * TclpGetTimeZone -- * - * This procedure return scale to convert click values from the - * TclpGetWideClicks native resolution to microsecond resolution - * and back. + * Determines the current timezone. The method varies wildly between + * different platform implementations, so its hidden in this function. * * Results: - * 1 click in microseconds as double. + * The return value is the local time zone, measured in minutes away from + * GMT (-ve for east, +ve for west). * * Side effects: * None. @@ -280,33 +239,103 @@ TclpWideClicksToNanoseconds( *---------------------------------------------------------------------- */ -double -TclpWideClickInMicrosec(void) +int +TclpGetTimeZone( + unsigned long currentTime) { - if (!IsTimeNative()) { - return 1.0; - } else { -#ifdef MAC_OSX_TCL - static int initialized = 0; - static double scale = 0.0; + int timeZone; - if (initialized) { - return scale; - } else { - mach_timebase_info_data_t tb; + /* + * 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. + */ - mach_timebase_info(&tb); - /* value of tb.numer / tb.denom = 1 click in nanoseconds */ - scale = ((double)tb.numer) / tb.denom / 1000; - initialized = 1; - return scale; - } -#else -#error Wide high-resolution clicks not implemented on this platform -#endif /* MAC_OSX_TCL */ +#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(&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(&curTime); + + timeZone = -(timeDataPtr->tm_gmtoff / 60); + if (timeDataPtr->tm_isdst) { + timeZone += 60; + } +#endif + +#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. + */ + + SetTZIfNecessary(); + + /* + * 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(&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; } + + /* + * 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 */ /* *---------------------------------------------------------------------- @@ -332,7 +361,7 @@ void Tcl_GetTime( Tcl_Time *timePtr) /* Location to store time information. */ { - GetTime(timePtr); + (*tclGetTimeProcPtr) (timePtr, tclTimeClientData); } /* @@ -353,10 +382,9 @@ Tcl_GetTime( *---------------------------------------------------------------------- */ -#ifndef TCL_NO_DEPRECATED struct tm * TclpGetDate( - const time_t *time, + CONST time_t *time, int useGMT) { if (useGMT) { @@ -384,7 +412,7 @@ TclpGetDate( struct tm * TclpGmtime( - const time_t *timePtr) /* Pointer to the number of seconds since the + CONST time_t *timePtr) /* Pointer to the number of seconds since the * local system's epoch */ { /* @@ -394,14 +422,14 @@ TclpGmtime( 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(&(tsdPtr->gmtime_buf), gmtime(timePtr), sizeof(struct tm)); Tcl_MutexUnlock(&tmMutex); #endif - return &tsdPtr->gmtime_buf; + return &(tsdPtr->gmtime_buf); } /* @@ -423,7 +451,7 @@ TclpGmtime( struct tm * TclpLocaltime( - const time_t *timePtr) /* Pointer to the number of seconds since the + CONST time_t *timePtr) /* Pointer to the number of seconds since the * local system's epoch */ { /* @@ -434,16 +462,15 @@ TclpLocaltime( 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(&(tsdPtr->localtime_buf), localtime(timePtr), sizeof(struct tm)); Tcl_MutexUnlock(&tmMutex); #endif - return &tsdPtr->localtime_buf; + return &(tsdPtr->localtime_buf); } -#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- @@ -466,7 +493,7 @@ void Tcl_SetTimeProc( Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, - void *clientData) + ClientData clientData) { tclGetTimeProcPtr = getProc; tclScaleTimeProcPtr = scaleProc; @@ -493,7 +520,7 @@ void Tcl_QueryTimeProc( Tcl_GetTimeProc **getProc, Tcl_ScaleTimeProc **scaleProc, - void **clientData) + ClientData *clientData) { if (getProc) { *getProc = tclGetTimeProcPtr; @@ -525,8 +552,8 @@ Tcl_QueryTimeProc( static void NativeScaleTime( - TCL_UNUSED(Tcl_Time *), - TCL_UNUSED(void *)) + Tcl_Time *timePtr, + ClientData clientData) { /* Native scale is 1:1. Nothing is done */ } @@ -551,7 +578,7 @@ NativeScaleTime( static void NativeGetTime( Tcl_Time *timePtr, - TCL_UNUSED(void *)) + ClientData clientData) { struct timeval tv; @@ -578,11 +605,10 @@ NativeGetTime( *---------------------------------------------------------------------- */ -#ifndef TCL_NO_DEPRECATED static void SetTZIfNecessary(void) { - const char *newTZ = getenv("TZ"); + CONST char *newTZ = getenv("TZ"); Tcl_MutexLock(&tmMutex); if (newTZ == NULL) { @@ -591,11 +617,11 @@ SetTZIfNecessary(void) if (lastTZ == NULL || strcmp(lastTZ, newTZ)) { tzset(); if (lastTZ == NULL) { - Tcl_CreateExitHandler(CleanupMemory, NULL); + Tcl_CreateExitHandler(CleanupMemory, (ClientData) NULL); } else { - ckfree(lastTZ); + Tcl_Free(lastTZ); } - lastTZ = (char *) ckalloc(strlen(newTZ) + 1); + lastTZ = ckalloc(strlen(newTZ) + 1); strcpy(lastTZ, newTZ); } Tcl_MutexUnlock(&tmMutex); @@ -620,11 +646,10 @@ SetTZIfNecessary(void) static void CleanupMemory( - TCL_UNUSED(void *)) + ClientData ignored) { ckfree(lastTZ); } -#endif /* TCL_NO_DEPRECATED */ /* * Local Variables: |
