tclUnixTime.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:11k
- /*
- * tclUnixTime.c --
- *
- * Contains Unix specific versions of Tcl functions that
- * obtain time values from the operating system.
- *
- * 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.
- *
- * RCS: @(#) $Id: tclUnixTime.c,v 1.15.2.6 2007/04/21 19:52:15 kennykb Exp $
- */
- #include "tclInt.h"
- #include "tclPort.h"
- #include <locale.h>
- #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.
- */
- static Tcl_ThreadDataKey tmKey;
- typedef struct ThreadSpecificData {
- struct tm gmtime_buf;
- struct tm localtime_buf;
- } ThreadSpecificData;
- /*
- * If we fall back on the thread-unsafe versions of gmtime and localtime,
- * use this mutex to try to protect them.
- */
- TCL_DECLARE_MUTEX(tmMutex)
- static char* lastTZ = NULL; /* Holds the last setting of the
- * TZ environment variable, or an
- * empty string if the variable was
- * not set. */
- /* Static functions declared in this file */
- static void SetTZIfNecessary _ANSI_ARGS_((void));
- static void CleanupMemory _ANSI_ARGS_((ClientData));
- /*
- *-----------------------------------------------------------------------------
- *
- * 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 time((time_t *) NULL);
- }
- /*
- *-----------------------------------------------------------------------------
- *
- * TclpGetClicks --
- *
- * This procedure returns a 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.
- *
- * Results:
- * Number of clicks from some start time.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
- unsigned long
- TclpGetClicks()
- {
- unsigned long now;
- #ifdef NO_GETTOD
- struct tms dummy;
- #else
- struct timeval date;
- struct timezone tz;
- #endif
- #ifdef NO_GETTOD
- now = (unsigned long) times(&dummy);
- #else
- gettimeofday(&date, &tz);
- now = date.tv_sec*1000000 + date.tv_usec;
- #endif
- return now;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TclpGetTimeZone --
- *
- * Determines the current timezone. The method varies wildly
- * between different platform implementations, so its hidden in
- * this function.
- *
- * Results:
- * The return value is the local time zone, measured in
- * minutes away from GMT (-ve for east, +ve for west).
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int
- TclpGetTimeZone (currentTime)
- Tcl_WideInt currentTime;
- {
- /*
- * 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.
- */
-
- #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);
- int timeZone;
- timeZone = timeDataPtr->tm_tzadj / 60;
- if (timeDataPtr->tm_isdst) {
- timeZone += 60;
- }
-
- return timeZone;
- #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);
- int timeZone;
- timeZone = -(timeDataPtr->tm_gmtoff / 60);
- if (timeDataPtr->tm_isdst) {
- timeZone += 60;
- }
-
- return timeZone;
- #endif
- #if defined(HAVE_TIMEZONE_VAR) && !defined(TCL_GOT_TIMEZONE) && !defined(USE_DELTA_FOR_TZ)
- # define TCL_GOT_TIMEZONE
- int 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;
- return timeZone;
- #endif
- #if !defined(TCL_GOT_TIMEZONE)
- #define TCL_GOT_TIMEZONE 1
- /*
- * Fallback - determine time zone with a known reference time.
- */
- int timeZone;
- 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 timeZone; /* eg +360 for CST6CDT */
- #endif
- #ifndef TCL_GOT_TIMEZONE
- /*
- * Cause compile error, we don't know how to get timezone.
- */
- #error autoconf did not figure out how to determine the timezone.
- #endif
- }
- /*
- *----------------------------------------------------------------------
- *
- * Tcl_GetTime --
- *
- * 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
- Tcl_GetTime(timePtr)
- Tcl_Time *timePtr; /* Location to store time information. */
- {
- struct timeval tv;
- struct timezone tz;
-
- (void) gettimeofday(&tv, &tz);
- timePtr->sec = tv.tv_sec;
- timePtr->usec = tv.tv_usec;
- }
- /*
- *----------------------------------------------------------------------
- *
- * 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(time, useGMT)
- TclpTime_t time;
- int useGMT;
- {
- if (useGMT) {
- return TclpGmtime(time);
- } else {
- return TclpLocaltime(time);
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * 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.
- *
- * Results:
- * Returns a pointer to a 'struct tm' in thread-specific data.
- *
- * Side effects:
- * Invokes gmtime or gmtime_r as appropriate.
- *
- *----------------------------------------------------------------------
- */
- struct tm *
- 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 ));
- #else
- Tcl_MutexLock( &tmMutex );
- memcpy( (VOID *) &( tsdPtr->gmtime_buf ),
- (VOID *) gmtime( timePtr ),
- sizeof( struct tm ) );
- Tcl_MutexUnlock( &tmMutex );
- #endif
- return &( tsdPtr->gmtime_buf );
- }
- /*
- * Forwarder for obsolete item in Stubs
- */
- struct tm*
- TclpGmtime_unix( timePtr )
- TclpTime_t_CONST timePtr;
- {
- return TclpGmtime( timePtr );
- }
- /*
- *----------------------------------------------------------------------
- *
- * TclpLocaltime --
- *
- * Wrapper around the 'localtime' library function to make it thread
- * safe.
- *
- * Results:
- * Returns a pointer to a 'struct tm' in thread-specific data.
- *
- * Side effects:
- * Invokes localtime or localtime_r as appropriate.
- *
- *----------------------------------------------------------------------
- */
- struct tm *
- 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 ) );
- #else
- Tcl_MutexLock( &tmMutex );
- memcpy( (VOID *) &( tsdPtr -> localtime_buf ),
- (VOID *) localtime( timePtr ),
- sizeof( struct tm ) );
- Tcl_MutexUnlock( &tmMutex );
- #endif
- return &( tsdPtr->localtime_buf );
- }
- /*
- * Forwarder for obsolete item in Stubs
- */
- struct tm*
- TclpLocaltime_unix( timePtr )
- TclpTime_t_CONST timePtr;
- {
- return TclpLocaltime( timePtr );
- }
- /*
- *----------------------------------------------------------------------
- *
- * SetTZIfNecessary --
- *
- * Determines whether a call to 'tzset' is needed prior to the
- * next call to 'localtime' or examination of the 'timezone' variable.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If 'tzset' has never been called in the current process, or if
- * the value of the environment variable TZ has changed since the
- * last call to 'tzset', then 'tzset' is called again.
- *
- *----------------------------------------------------------------------
- */
- static void
- SetTZIfNecessary() {
- CONST char* newTZ = getenv( "TZ" );
- Tcl_MutexLock(&tmMutex);
- if ( newTZ == NULL ) {
- newTZ = "";
- }
- if ( lastTZ == NULL || strcmp( lastTZ, newTZ ) ) {
- tzset();
- if ( lastTZ == NULL ) {
- Tcl_CreateExitHandler( CleanupMemory, (ClientData) NULL );
- } else {
- Tcl_Free( lastTZ );
- }
- lastTZ = ckalloc( strlen( newTZ ) + 1 );
- strcpy( lastTZ, newTZ );
- }
- Tcl_MutexUnlock(&tmMutex);
- }
- /*
- *----------------------------------------------------------------------
- *
- * CleanupMemory --
- *
- * Releases the private copy of the TZ environment variable
- * upon exit from Tcl.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Frees allocated memory.
- *
- *----------------------------------------------------------------------
- */
- static void
- CleanupMemory( ClientData ignored )
- {
- ckfree( lastTZ );
- }