tclUnixTime.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:11k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclUnixTime.c --
  3.  *
  4.  * Contains Unix specific versions of Tcl functions that
  5.  * obtain time values from the operating system.
  6.  *
  7.  * Copyright (c) 1995 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tclUnixTime.c,v 1.15.2.6 2007/04/21 19:52:15 kennykb Exp $
  13.  */
  14. #include "tclInt.h"
  15. #include "tclPort.h"
  16. #include <locale.h>
  17. #define TM_YEAR_BASE 1900
  18. #define IsLeapYear(x)   ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0))
  19. /*
  20.  * TclpGetDate is coded to return a pointer to a 'struct tm'.  For
  21.  * thread safety, this structure must be in thread-specific data.
  22.  * The 'tmKey' variable is the key to this buffer.
  23.  */
  24. static Tcl_ThreadDataKey tmKey;
  25. typedef struct ThreadSpecificData {
  26.     struct tm gmtime_buf;
  27.     struct tm localtime_buf;
  28. } ThreadSpecificData;
  29. /*
  30.  * If we fall back on the thread-unsafe versions of gmtime and localtime,
  31.  * use this mutex to try to protect them.
  32.  */
  33. TCL_DECLARE_MUTEX(tmMutex)
  34. static char* lastTZ = NULL; /* Holds the last setting of the
  35.  * TZ environment variable, or an
  36.  * empty string if the variable was
  37.  * not set. */
  38. /* Static functions declared in this file */
  39. static void SetTZIfNecessary _ANSI_ARGS_((void));
  40. static void CleanupMemory _ANSI_ARGS_((ClientData));
  41. /*
  42.  *-----------------------------------------------------------------------------
  43.  *
  44.  * TclpGetSeconds --
  45.  *
  46.  * This procedure returns the number of seconds from the epoch.  On
  47.  * most Unix systems the epoch is Midnight Jan 1, 1970 GMT.
  48.  *
  49.  * Results:
  50.  * Number of seconds from the epoch.
  51.  *
  52.  * Side effects:
  53.  * None.
  54.  *
  55.  *-----------------------------------------------------------------------------
  56.  */
  57. unsigned long
  58. TclpGetSeconds()
  59. {
  60.     return time((time_t *) NULL);
  61. }
  62. /*
  63.  *-----------------------------------------------------------------------------
  64.  *
  65.  * TclpGetClicks --
  66.  *
  67.  * This procedure returns a value that represents the highest resolution
  68.  * clock available on the system.  There are no garantees on what the
  69.  * resolution will be.  In Tcl we will call this value a "click".  The
  70.  * start time is also system dependant.
  71.  *
  72.  * Results:
  73.  * Number of clicks from some start time.
  74.  *
  75.  * Side effects:
  76.  * None.
  77.  *
  78.  *-----------------------------------------------------------------------------
  79.  */
  80. unsigned long
  81. TclpGetClicks()
  82. {
  83.     unsigned long now;
  84. #ifdef NO_GETTOD
  85.     struct tms dummy;
  86. #else
  87.     struct timeval date;
  88.     struct timezone tz;
  89. #endif
  90. #ifdef NO_GETTOD
  91.     now = (unsigned long) times(&dummy);
  92. #else
  93.     gettimeofday(&date, &tz);
  94.     now = date.tv_sec*1000000 + date.tv_usec;
  95. #endif
  96.     return now;
  97. }
  98. /*
  99.  *----------------------------------------------------------------------
  100.  *
  101.  * TclpGetTimeZone --
  102.  *
  103.  * Determines the current timezone.  The method varies wildly
  104.  * between different platform implementations, so its hidden in
  105.  * this function.
  106.  *
  107.  * Results:
  108.  * The return value is the local time zone, measured in
  109.  * minutes away from GMT (-ve for east, +ve for west).
  110.  *
  111.  * Side effects:
  112.  * None.
  113.  *
  114.  *----------------------------------------------------------------------
  115.  */
  116. int
  117. TclpGetTimeZone (currentTime)
  118.     Tcl_WideInt  currentTime;
  119. {
  120.     /*
  121.      * We prefer first to use the time zone in "struct tm" if the
  122.      * structure contains such a member.  Following that, we try
  123.      * to locate the external 'timezone' variable and use its value.
  124.      * If both of those methods fail, we attempt to convert a known
  125.      * time to local time and use the difference from UTC as the local
  126.      * time zone.  In all cases, we need to undo any Daylight Saving Time
  127.      * adjustment.
  128.      */
  129.     
  130. #if defined(HAVE_TM_TZADJ)
  131. #   define TCL_GOT_TIMEZONE
  132.     /* Struct tm contains tm_tzadj - that value may be used. */
  133.     time_t      curTime = (time_t) currentTime;
  134.     struct tm  *timeDataPtr = TclpLocaltime((TclpTime_t) &curTime);
  135.     int         timeZone;
  136.     timeZone = timeDataPtr->tm_tzadj  / 60;
  137.     if (timeDataPtr->tm_isdst) {
  138.         timeZone += 60;
  139.     }
  140.     
  141.     return timeZone;
  142. #endif
  143. #if defined(HAVE_TM_GMTOFF) && !defined (TCL_GOT_TIMEZONE)
  144. #   define TCL_GOT_TIMEZONE
  145.     /* Struct tm contains tm_gmtoff - that value may be used. */
  146.     time_t     curTime = (time_t) currentTime;
  147.     struct tm *timeDataPtr = TclpLocaltime((TclpTime_t) &curTime);
  148.     int        timeZone;
  149.     timeZone = -(timeDataPtr->tm_gmtoff / 60);
  150.     if (timeDataPtr->tm_isdst) {
  151.         timeZone += 60;
  152.     }
  153.     
  154.     return timeZone;
  155. #endif
  156. #if defined(HAVE_TIMEZONE_VAR) && !defined(TCL_GOT_TIMEZONE) && !defined(USE_DELTA_FOR_TZ)
  157. #   define TCL_GOT_TIMEZONE
  158.     int        timeZone;
  159.     /* The 'timezone' external var is present and may be used. */
  160.     SetTZIfNecessary();
  161.     /*
  162.      * Note: this is not a typo in "timezone" below!  See tzset
  163.      * documentation for details.
  164.      */
  165.     timeZone = timezone / 60;
  166.     return timeZone;
  167. #endif
  168. #if !defined(TCL_GOT_TIMEZONE) 
  169. #define TCL_GOT_TIMEZONE 1
  170.     /*
  171.      * Fallback - determine time zone with a known reference time.
  172.      */
  173.     int timeZone;
  174.     time_t tt;
  175.     struct tm *stm;
  176.     tt = 849268800L;      /*    1996-11-29 12:00:00  GMT */
  177.     stm = TclpLocaltime((TclpTime_t) &tt); /* eg 1996-11-29  6:00:00  CST6CDT */
  178.     /* The calculation below assumes a max of +12 or -12 hours from GMT */
  179.     timeZone = (12 - stm->tm_hour)*60 + (0 - stm->tm_min);
  180.     if ( stm -> tm_isdst ) {
  181.         timeZone += 60;
  182.     }
  183.     return timeZone;  /* eg +360 for CST6CDT */
  184. #endif
  185. #ifndef TCL_GOT_TIMEZONE
  186.     /*
  187.      * Cause compile error, we don't know how to get timezone.
  188.      */
  189. #error autoconf did not figure out how to determine the timezone. 
  190. #endif
  191. }
  192. /*
  193.  *----------------------------------------------------------------------
  194.  *
  195.  * Tcl_GetTime --
  196.  *
  197.  * Gets the current system time in seconds and microseconds
  198.  * since the beginning of the epoch: 00:00 UCT, January 1, 1970.
  199.  *
  200.  * Results:
  201.  * Returns the current time in timePtr.
  202.  *
  203.  * Side effects:
  204.  * None.
  205.  *
  206.  *----------------------------------------------------------------------
  207.  */
  208. void
  209. Tcl_GetTime(timePtr)
  210.     Tcl_Time *timePtr; /* Location to store time information. */
  211. {
  212.     struct timeval tv;
  213.     struct timezone tz;
  214.     
  215.     (void) gettimeofday(&tv, &tz);
  216.     timePtr->sec = tv.tv_sec;
  217.     timePtr->usec = tv.tv_usec;
  218. }
  219. /*
  220.  *----------------------------------------------------------------------
  221.  *
  222.  * TclpGetDate --
  223.  *
  224.  * This function converts between seconds and struct tm.  If
  225.  * useGMT is true, then the returned date will be in Greenwich
  226.  * Mean Time (GMT).  Otherwise, it will be in the local time zone.
  227.  *
  228.  * Results:
  229.  * Returns a static tm structure.
  230.  *
  231.  * Side effects:
  232.  * None.
  233.  *
  234.  *----------------------------------------------------------------------
  235.  */
  236. struct tm *
  237. TclpGetDate(time, useGMT)
  238.     TclpTime_t time;
  239.     int useGMT;
  240. {
  241.     if (useGMT) {
  242. return TclpGmtime(time);
  243.     } else {
  244. return TclpLocaltime(time);
  245.     }
  246. }
  247. /*
  248.  *----------------------------------------------------------------------
  249.  *
  250.  * TclpStrftime --
  251.  *
  252.  * On Unix, we can safely call the native strftime implementation,
  253.  * and also ignore the useGMT parameter.
  254.  *
  255.  * Results:
  256.  * The normal strftime result.
  257.  *
  258.  * Side effects:
  259.  * None.
  260.  *
  261.  *----------------------------------------------------------------------
  262.  */
  263. size_t
  264. TclpStrftime(s, maxsize, format, t, useGMT)
  265.     char *s;
  266.     size_t maxsize;
  267.     CONST char *format;
  268.     CONST struct tm *t;
  269.     int useGMT;
  270. {
  271.     if (format[0] == '%' && format[1] == 'Q') {
  272. /* Format as a stardate */
  273. sprintf(s, "Stardate %2d%03d.%01d",
  274. (((t->tm_year + TM_YEAR_BASE) + 377) - 2323),
  275. (((t->tm_yday + 1) * 1000) /
  276. (365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))),
  277. (((t->tm_hour * 60) + t->tm_min)/144));
  278. return(strlen(s));
  279.     }
  280.     setlocale(LC_TIME, "");
  281.     return strftime(s, maxsize, format, t);
  282. }
  283. /*
  284.  *----------------------------------------------------------------------
  285.  *
  286.  * TclpGmtime --
  287.  *
  288.  * Wrapper around the 'gmtime' library function to make it thread
  289.  * safe.
  290.  *
  291.  * Results:
  292.  * Returns a pointer to a 'struct tm' in thread-specific data.
  293.  *
  294.  * Side effects:
  295.  * Invokes gmtime or gmtime_r as appropriate.
  296.  *
  297.  *----------------------------------------------------------------------
  298.  */
  299. struct tm *
  300. TclpGmtime( tt )
  301.     TclpTime_t_CONST tt;
  302. {
  303.     CONST time_t *timePtr = (CONST time_t *) tt;
  304. /* Pointer to the number of seconds
  305.  * since the local system's epoch */
  306.     /*
  307.      * Get a thread-local buffer to hold the returned time.
  308.      */
  309.     ThreadSpecificData *tsdPtr = TCL_TSD_INIT( &tmKey );
  310. #ifdef HAVE_GMTIME_R
  311.     gmtime_r(timePtr, &( tsdPtr->gmtime_buf ));
  312. #else
  313.     Tcl_MutexLock( &tmMutex );
  314.     memcpy( (VOID *) &( tsdPtr->gmtime_buf ),
  315.     (VOID *) gmtime( timePtr ),
  316.     sizeof( struct tm ) );
  317.     Tcl_MutexUnlock( &tmMutex );
  318. #endif    
  319.     return &( tsdPtr->gmtime_buf );
  320. }
  321. /*
  322.  * Forwarder for obsolete item in Stubs
  323.  */
  324. struct tm*
  325. TclpGmtime_unix( timePtr )
  326.     TclpTime_t_CONST timePtr;
  327. {
  328.     return TclpGmtime( timePtr );
  329. }
  330. /*
  331.  *----------------------------------------------------------------------
  332.  *
  333.  * TclpLocaltime --
  334.  *
  335.  * Wrapper around the 'localtime' library function to make it thread
  336.  * safe.
  337.  *
  338.  * Results:
  339.  * Returns a pointer to a 'struct tm' in thread-specific data.
  340.  *
  341.  * Side effects:
  342.  * Invokes localtime or localtime_r as appropriate.
  343.  *
  344.  *----------------------------------------------------------------------
  345.  */
  346. struct tm *
  347. TclpLocaltime( tt )
  348.     TclpTime_t_CONST tt;
  349. {
  350.     CONST time_t *timePtr = (CONST time_t *) tt;
  351. /* Pointer to the number of seconds
  352.  * since the local system's epoch */
  353.     /*
  354.      * Get a thread-local buffer to hold the returned time.
  355.      */
  356.     ThreadSpecificData *tsdPtr = TCL_TSD_INIT( &tmKey );
  357.     SetTZIfNecessary();
  358. #ifdef HAVE_LOCALTIME_R
  359.     localtime_r( timePtr, &( tsdPtr->localtime_buf ) );
  360. #else
  361.     Tcl_MutexLock( &tmMutex );
  362.     memcpy( (VOID *) &( tsdPtr -> localtime_buf ),
  363.     (VOID *) localtime( timePtr ),
  364.     sizeof( struct tm ) );
  365.     Tcl_MutexUnlock( &tmMutex );
  366. #endif    
  367.     return &( tsdPtr->localtime_buf );
  368. }
  369. /*
  370.  * Forwarder for obsolete item in Stubs
  371.  */
  372. struct tm*
  373. TclpLocaltime_unix( timePtr )
  374.     TclpTime_t_CONST timePtr;
  375. {
  376.     return TclpLocaltime( timePtr );
  377. }
  378. /*
  379.  *----------------------------------------------------------------------
  380.  *
  381.  * SetTZIfNecessary --
  382.  *
  383.  * Determines whether a call to 'tzset' is needed prior to the
  384.  * next call to 'localtime' or examination of the 'timezone' variable.
  385.  *
  386.  * Results:
  387.  * None.
  388.  *
  389.  * Side effects:
  390.  * If 'tzset' has never been called in the current process, or if
  391.  * the value of the environment variable TZ has changed since the
  392.  * last call to 'tzset', then 'tzset' is called again.
  393.  *
  394.  *----------------------------------------------------------------------
  395.  */
  396. static void
  397. SetTZIfNecessary() {
  398.     CONST char* newTZ = getenv( "TZ" );
  399.     Tcl_MutexLock(&tmMutex);
  400.     if ( newTZ == NULL ) {
  401. newTZ = "";
  402.     }
  403.     if ( lastTZ == NULL || strcmp( lastTZ, newTZ ) ) {
  404.         tzset();
  405. if ( lastTZ == NULL ) {
  406.     Tcl_CreateExitHandler( CleanupMemory, (ClientData) NULL );
  407. } else {
  408.     Tcl_Free( lastTZ );
  409. }
  410. lastTZ = ckalloc( strlen( newTZ ) + 1 );
  411. strcpy( lastTZ, newTZ );
  412.     }
  413.     Tcl_MutexUnlock(&tmMutex);
  414. }
  415. /*
  416.  *----------------------------------------------------------------------
  417.  *
  418.  * CleanupMemory --
  419.  *
  420.  * Releases the private copy of the TZ environment variable
  421.  * upon exit from Tcl.
  422.  *
  423.  * Results:
  424.  * None.
  425.  *
  426.  * Side effects:
  427.  * Frees allocated memory.
  428.  *
  429.  *----------------------------------------------------------------------
  430.  */
  431. static void
  432. CleanupMemory( ClientData ignored )
  433. {
  434.     ckfree( lastTZ );
  435. }