summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog33
-rw-r--r--generic/tclClock.c4
-rw-r--r--generic/tclInt.decls17
-rw-r--r--generic/tclIntDecls.h22
-rw-r--r--generic/tclIntPlatDecls.h30
-rw-r--r--generic/tclStubInit.c8
-rw-r--r--tests/clock.test23
-rw-r--r--unix/tclUnixPort.h10
-rw-r--r--unix/tclUnixThrd.c47
-rw-r--r--unix/tclUnixTime.c251
-rw-r--r--win/tclWinTime.c66
11 files changed, 343 insertions, 168 deletions
diff --git a/ChangeLog b/ChangeLog
index c0bb25b..66885c4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2004-05-14 Kevin B. Kenny <kennykb@acm.org>
+
+ * generic/tclInt.decls: Promoted TclpLocaltime and TclpGmtime
+ * generic/tclIntDecls.h: from Unix-specific stubs to the generic
+ * generic/tclIntPlatDecls.h: internal Stubs table. Reran 'genstubs'
+ * generic/tclStubInit.c:
+ * unix/tclUnixPort.h:
+
+ * generic/tclClock.c: Changed a buggy 'GMT' timezone specification
+ to the correct 'GMT0'. [Bug #922848]
+
+ * unix/tclUnixThrd.c: Moved TclpGmtime and TclpLocaltime to
+ unix/tclUnixTime.c where they belong.
+
+ * unix/tclUnixTime.c (TclpGmtime, TclpLocaltime, TclpGetTimeZone,
+ ThreadSafeGMTime [removed],
+ ThreadSafeLocalTime [removed],
+ SetTZIfNecessary, CleanupMemory):
+ Restructured to make sure that the same mutex protects
+ all calls to localtime, gmtime, and tzset. Added a check
+ in front of those calls to make sure that the TZ env var
+ hasn't changed since the last call to tzset, and repeat
+ tzset if necessary. [Bug #942078] Removed a buggy test
+ of the Daylight Saving Time information in 'gettimeofday'
+ in favor of applying 'localtime' to a known value.
+ [Bug #922848]
+
+ * tests/clock.test (clock-3.14): Added test to make sure that
+ changes to $env(TZ) take effect immediately.
+
+ * win/tclWinTime.c (TclpLocaltime, TclpGmtime):
+ Added porting layer for 'localtime' and 'gmtime' calls.
+
2004-05-14 Miguel Sofer <msofer@users.sf.net>
* generic/tclExecute.h:
diff --git a/generic/tclClock.c b/generic/tclClock.c
index 6d23006..67570df 100644
--- a/generic/tclClock.c
+++ b/generic/tclClock.c
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclClock.c,v 1.27 2004/04/15 21:06:39 dkf Exp $
+ * RCS: @(#) $Id: tclClock.c,v 1.28 2004/05/14 21:43:28 kennykb Exp $
*/
#include "tclInt.h"
@@ -313,7 +313,7 @@ FormatClock(interp, clockVal, useGMT, format)
} else {
savedTZEnv = NULL;
}
- Tcl_SetVar2(interp, "env", "TZ", "GMT", TCL_GLOBAL_ONLY);
+ Tcl_SetVar2(interp, "env", "TZ", "GMT0", TCL_GLOBAL_ONLY);
savedTimeZone = timezone;
timezone = 0;
tzset();
diff --git a/generic/tclInt.decls b/generic/tclInt.decls
index 6a98616..4a7e787 100644
--- a/generic/tclInt.decls
+++ b/generic/tclInt.decls
@@ -12,7 +12,7 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: tclInt.decls,v 1.72 2004/05/13 20:31:07 dkf Exp $
+# RCS: @(#) $Id: tclInt.decls,v 1.73 2004/05/14 21:43:29 kennykb Exp $
library tcl
@@ -736,6 +736,15 @@ declare 181 generic {
CONST char *file, int line)
}
+# TclpGmtime and TclpLocaltime promoted to the generic interface from unix
+
+declare 182 generic {
+ struct tm *TclpLocaltime(CONST time_t *clock)
+}
+declare 183 generic {
+ struct tm *TclpGmtime(CONST time_t *clock)
+}
+
##############################################################################
# Define the platform specific internal Tcl interface. These functions are
@@ -904,11 +913,13 @@ declare 9 unix {
declare 10 unix {
Tcl_DirEntry *TclpReaddir(DIR *dir)
}
+# Slots 11 and 12 are forwarders for functions that were promoted to
+# generic Stubs
declare 11 unix {
- struct tm *TclpLocaltime(time_t *clock)
+ struct tm *TclpLocaltime_unix(CONST time_t *clock)
}
declare 12 unix {
- struct tm *TclpGmtime(time_t *clock)
+ struct tm *TclpGmtime_unix(CONST time_t *clock)
}
declare 13 unix {
char *TclpInetNtoa(struct in_addr addr)
diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h
index 09e193d..3b6fbfb 100644
--- a/generic/tclIntDecls.h
+++ b/generic/tclIntDecls.h
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclIntDecls.h,v 1.61 2004/03/19 18:43:15 dgp Exp $
+ * RCS: @(#) $Id: tclIntDecls.h,v 1.62 2004/05/14 21:43:29 kennykb Exp $
*/
#ifndef _TCLINTDECLS
@@ -959,6 +959,16 @@ EXTERN Tcl_Obj * TclNewListObjDirect _ANSI_ARGS_((int objc,
EXTERN Tcl_Obj * TclDbNewListObjDirect _ANSI_ARGS_((int objc,
Tcl_Obj ** objv, CONST char * file, int line));
#endif
+#ifndef TclpLocaltime_TCL_DECLARED
+#define TclpLocaltime_TCL_DECLARED
+/* 182 */
+EXTERN struct tm * TclpLocaltime _ANSI_ARGS_((CONST time_t * clock));
+#endif
+#ifndef TclpGmtime_TCL_DECLARED
+#define TclpGmtime_TCL_DECLARED
+/* 183 */
+EXTERN struct tm * TclpGmtime _ANSI_ARGS_((CONST time_t * clock));
+#endif
typedef struct TclIntStubs {
int magic;
@@ -1161,6 +1171,8 @@ typedef struct TclIntStubs {
Tcl_Obj * (*tcl_GetStartupScript) _ANSI_ARGS_((CONST char ** encodingNamePtr)); /* 179 */
Tcl_Obj * (*tclNewListObjDirect) _ANSI_ARGS_((int objc, Tcl_Obj ** objv)); /* 180 */
Tcl_Obj * (*tclDbNewListObjDirect) _ANSI_ARGS_((int objc, Tcl_Obj ** objv, CONST char * file, int line)); /* 181 */
+ struct tm * (*tclpLocaltime) _ANSI_ARGS_((CONST time_t * clock)); /* 182 */
+ struct tm * (*tclpGmtime) _ANSI_ARGS_((CONST time_t * clock)); /* 183 */
} TclIntStubs;
#ifdef __cplusplus
@@ -1797,6 +1809,14 @@ extern TclIntStubs *tclIntStubsPtr;
#define TclDbNewListObjDirect \
(tclIntStubsPtr->tclDbNewListObjDirect) /* 181 */
#endif
+#ifndef TclpLocaltime
+#define TclpLocaltime \
+ (tclIntStubsPtr->tclpLocaltime) /* 182 */
+#endif
+#ifndef TclpGmtime
+#define TclpGmtime \
+ (tclIntStubsPtr->tclpGmtime) /* 183 */
+#endif
#endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */
diff --git a/generic/tclIntPlatDecls.h b/generic/tclIntPlatDecls.h
index 0d5bf30..3477646 100644
--- a/generic/tclIntPlatDecls.h
+++ b/generic/tclIntPlatDecls.h
@@ -9,7 +9,7 @@
* Copyright (c) 1998-1999 by Scriptics Corporation.
* All rights reserved.
*
- * RCS: @(#) $Id: tclIntPlatDecls.h,v 1.22 2004/03/17 18:14:13 das Exp $
+ * RCS: @(#) $Id: tclIntPlatDecls.h,v 1.23 2004/05/14 21:43:29 kennykb Exp $
*/
#ifndef _TCLINTPLATDECLS
@@ -91,15 +91,15 @@ EXTERN TclFile TclpCreateTempFile _ANSI_ARGS_((
/* 10 */
EXTERN Tcl_DirEntry * TclpReaddir _ANSI_ARGS_((DIR * dir));
#endif
-#ifndef TclpLocaltime_TCL_DECLARED
-#define TclpLocaltime_TCL_DECLARED
+#ifndef TclpLocaltime_unix_TCL_DECLARED
+#define TclpLocaltime_unix_TCL_DECLARED
/* 11 */
-EXTERN struct tm * TclpLocaltime _ANSI_ARGS_((time_t * clock));
+EXTERN struct tm * TclpLocaltime_unix _ANSI_ARGS_((CONST time_t * clock));
#endif
-#ifndef TclpGmtime_TCL_DECLARED
-#define TclpGmtime_TCL_DECLARED
+#ifndef TclpGmtime_unix_TCL_DECLARED
+#define TclpGmtime_unix_TCL_DECLARED
/* 12 */
-EXTERN struct tm * TclpGmtime _ANSI_ARGS_((time_t * clock));
+EXTERN struct tm * TclpGmtime_unix _ANSI_ARGS_((CONST time_t * clock));
#endif
#ifndef TclpInetNtoa_TCL_DECLARED
#define TclpInetNtoa_TCL_DECLARED
@@ -300,8 +300,8 @@ typedef struct TclIntPlatStubs {
int (*tclUnixWaitForFile) _ANSI_ARGS_((int fd, int mask, int timeout)); /* 8 */
TclFile (*tclpCreateTempFile) _ANSI_ARGS_((CONST char * contents)); /* 9 */
Tcl_DirEntry * (*tclpReaddir) _ANSI_ARGS_((DIR * dir)); /* 10 */
- struct tm * (*tclpLocaltime) _ANSI_ARGS_((time_t * clock)); /* 11 */
- struct tm * (*tclpGmtime) _ANSI_ARGS_((time_t * clock)); /* 12 */
+ struct tm * (*tclpLocaltime_unix) _ANSI_ARGS_((CONST time_t * clock)); /* 11 */
+ struct tm * (*tclpGmtime_unix) _ANSI_ARGS_((CONST time_t * clock)); /* 12 */
char * (*tclpInetNtoa) _ANSI_ARGS_((struct in_addr addr)); /* 13 */
int (*tclUnixCopyFile) _ANSI_ARGS_((CONST char * src, CONST char * dst, CONST Tcl_StatBuf * statBufPtr, int dontCopyAtts)); /* 14 */
#endif /* UNIX */
@@ -399,13 +399,13 @@ extern TclIntPlatStubs *tclIntPlatStubsPtr;
#define TclpReaddir \
(tclIntPlatStubsPtr->tclpReaddir) /* 10 */
#endif
-#ifndef TclpLocaltime
-#define TclpLocaltime \
- (tclIntPlatStubsPtr->tclpLocaltime) /* 11 */
+#ifndef TclpLocaltime_unix
+#define TclpLocaltime_unix \
+ (tclIntPlatStubsPtr->tclpLocaltime_unix) /* 11 */
#endif
-#ifndef TclpGmtime
-#define TclpGmtime \
- (tclIntPlatStubsPtr->tclpGmtime) /* 12 */
+#ifndef TclpGmtime_unix
+#define TclpGmtime_unix \
+ (tclIntPlatStubsPtr->tclpGmtime_unix) /* 12 */
#endif
#ifndef TclpInetNtoa
#define TclpInetNtoa \
diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c
index 19266e0..8f6e4c2 100644
--- a/generic/tclStubInit.c
+++ b/generic/tclStubInit.c
@@ -8,7 +8,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclStubInit.c,v 1.95 2004/05/13 13:00:20 dkf Exp $
+ * RCS: @(#) $Id: tclStubInit.c,v 1.96 2004/05/14 21:43:29 kennykb Exp $
*/
#include "tclInt.h"
@@ -266,6 +266,8 @@ TclIntStubs tclIntStubs = {
Tcl_GetStartupScript, /* 179 */
TclNewListObjDirect, /* 180 */
TclDbNewListObjDirect, /* 181 */
+ TclpLocaltime, /* 182 */
+ TclpGmtime, /* 183 */
};
TclIntPlatStubs tclIntPlatStubs = {
@@ -283,8 +285,8 @@ TclIntPlatStubs tclIntPlatStubs = {
TclUnixWaitForFile, /* 8 */
TclpCreateTempFile, /* 9 */
TclpReaddir, /* 10 */
- TclpLocaltime, /* 11 */
- TclpGmtime, /* 12 */
+ TclpLocaltime_unix, /* 11 */
+ TclpGmtime_unix, /* 12 */
TclpInetNtoa, /* 13 */
TclUnixCopyFile, /* 14 */
#endif /* UNIX */
diff --git a/tests/clock.test b/tests/clock.test
index ea7310e..5f1b028 100644
--- a/tests/clock.test
+++ b/tests/clock.test
@@ -10,7 +10,7 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: clock.test,v 1.25 2004/04/15 21:06:39 dkf Exp $
+# RCS: @(#) $Id: clock.test,v 1.26 2004/05/14 21:43:29 kennykb Exp $
set env(LC_TIME) POSIX
@@ -173,6 +173,27 @@ test clock-3.13 {clock format with non-ASCII character in the format string} {
set res
} "\u00c4"
+# Bug 942078
+
+test clock-3.14 {change of time zone} -setup {
+ catch { unset oldTZ }
+ if { [info exists env(TZ)] } {
+ set oldTZ $env(TZ)
+ }
+} -body {
+ set env(TZ) PST8PDT
+ set s [clock format 0 -format %H%M]
+ set env(TZ) GMT0
+ append s -[clock format 0 -format %H%M]
+} -cleanup {
+ if { [info exists oldTZ] } {
+ set env(TZ) $oldTZ
+ unset oldTZ
+ } else {
+ unset env(TZ)
+ }
+} -result {1600-0000}
+
# clock scan
test clock-4.1 {clock scan tests} {
list [catch {clock scan} msg] $msg
diff --git a/unix/tclUnixPort.h b/unix/tclUnixPort.h
index e1b2fc4..8bb93bf 100644
--- a/unix/tclUnixPort.h
+++ b/unix/tclUnixPort.h
@@ -19,7 +19,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclUnixPort.h,v 1.35 2004/04/06 22:25:57 dgp Exp $
+ * RCS: @(#) $Id: tclUnixPort.h,v 1.36 2004/05/14 21:43:29 kennykb Exp $
*/
#ifndef _TCLUNIXPORT
@@ -557,12 +557,12 @@ EXTERN void TclpMutexInit _ANSI_ARGS_((TclpMutex *mPtr));
EXTERN void TclpMutexLock _ANSI_ARGS_((TclpMutex *mPtr));
EXTERN void TclpMutexUnlock _ANSI_ARGS_((TclpMutex *mPtr));
EXTERN Tcl_DirEntry * TclpReaddir(DIR *);
-EXTERN struct tm * TclpLocaltime(time_t *);
-EXTERN struct tm * TclpGmtime(time_t *);
+EXTERN struct tm * TclpLocaltime(CONST time_t *);
+EXTERN struct tm * TclpGmtime(CONST time_t *);
EXTERN char * TclpInetNtoa(struct in_addr);
#define readdir(x) TclpReaddir(x)
-#define localtime(x) TclpLocaltime(x)
-#define gmtime(x) TclpGmtime(x)
+/* #define localtime(x) TclpLocaltime(x)
+ * #define gmtime(x) TclpGmtime(x) */
#undef inet_ntoa
#define inet_ntoa(x) TclpInetNtoa(x)
#undef TclOSreaddir
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c
index c087423..3de2319 100644
--- a/unix/tclUnixThrd.c
+++ b/unix/tclUnixThrd.c
@@ -20,8 +20,6 @@
typedef struct ThreadSpecificData {
char nabuf[16];
- struct tm gtbuf;
- struct tm ltbuf;
struct {
Tcl_DirEntry ent;
char name[MAXNAMLEN+1];
@@ -863,51 +861,6 @@ TclpReaddir(DIR * dir)
#endif
return ent;
}
-
-#if defined(TCL_THREADS) && (!defined(HAVE_GMTIME_R) || !defined(HAVE_LOCALTIME_R))
-TCL_DECLARE_MUTEX( tmMutex )
-#undef localtime
-#undef gmtime
-#endif
-
-struct tm *
-TclpLocaltime(time_t * clock)
-{
-#ifdef TCL_THREADS
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
-#ifdef HAVE_LOCALTIME_R
- return localtime_r(clock, &tsdPtr->ltbuf);
-#else
- Tcl_MutexLock( &tmMutex );
- memcpy( (VOID *) &tsdPtr->ltbuf, (VOID *) localtime( clock ), sizeof (struct tm) );
- Tcl_MutexUnlock( &tmMutex );
- return &tsdPtr->ltbuf;
-#endif
-#else
- return localtime(clock);
-#endif
-}
-
-struct tm *
-TclpGmtime(time_t * clock)
-{
-#ifdef TCL_THREADS
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
-#ifdef HAVE_GMTIME_R
- return gmtime_r(clock, &tsdPtr->gtbuf);
-#else
- Tcl_MutexLock( &tmMutex );
- memcpy( (VOID *) &tsdPtr->gtbuf, (VOID *) gmtime( clock ), sizeof (struct tm) );
- Tcl_MutexUnlock( &tmMutex );
- return &tsdPtr->gtbuf;
-#endif
-#else
- return gmtime(clock);
-#endif
-}
-
char *
TclpInetNtoa(struct in_addr addr)
{
diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c
index 37c16bc..6def210 100644
--- a/unix/tclUnixTime.c
+++ b/unix/tclUnixTime.c
@@ -9,7 +9,7 @@
* 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.20 2004/04/06 22:25:57 dgp Exp $
+ * RCS: @(#) $Id: tclUnixTime.c,v 1.21 2004/05/14 21:43:29 kennykb Exp $
*/
#include "tclInt.h"
@@ -24,22 +24,27 @@
*/
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.
*/
-#if !defined(HAVE_GMTIME_R) || !defined(HAVE_LOCALTIME_R)
TCL_DECLARE_MUTEX(tmMutex)
-#endif
-/*
- * Forward declarations for procedures defined later in this file.
- */
+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 struct tm *ThreadSafeGMTime _ANSI_ARGS_(( CONST time_t* ));
-static struct tm *ThreadSafeLocalTime _ANSI_ARGS_(( CONST time_t* ));
+static void SetTZIfNecessary _ANSI_ARGS_((void));
+static void CleanupMemory _ANSI_ARGS_((ClientData));
/*
*-----------------------------------------------------------------------------
@@ -128,18 +133,22 @@ TclpGetTimeZone (currentTime)
unsigned long currentTime;
{
/*
- * Determine how a timezone is obtained from "struct tm". If there is no
- * time zone in this struct (very lame) then use the timezone variable.
- * This is done in a way to make the timezone variable the method of last
- * resort, as some systems have it in addition to a field in "struct tm".
- * The gettimeofday system call can also be used to determine the time
- * zone.
+ * 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 = ThreadSafeLocalTime(&curTime);
+ struct tm *timeDataPtr = TclpLocaltime(&curTime);
int timeZone;
timeZone = timeDataPtr->tm_tzadj / 60;
@@ -148,12 +157,16 @@ TclpGetTimeZone (currentTime)
}
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 = ThreadSafeLocalTime(&curTime);
+ struct tm *timeDataPtr = TclpLocaltime(&curTime);
int timeZone;
timeZone = -(timeDataPtr->tm_gmtoff / 60);
@@ -162,46 +175,17 @@ TclpGetTimeZone (currentTime)
}
return timeZone;
-#endif
-
-#if defined(USE_DELTA_FOR_TZ)
-#define TCL_GOT_TIMEZONE 1
- /*
- * This hack replaces using global var timezone or gettimeofday
- * in situations where they are buggy such as on AIX when libbsd.a
- * is linked in.
- */
- int timeZone;
- time_t tt;
- struct tm *stm;
- tt = 849268800L; /* 1996-11-29 12:00:00 GMT */
- stm = ThreadSafeLocalTime(&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);
- return timeZone; /* eg +360 for CST6CDT */
#endif
- /*
- * Must prefer timezone variable over gettimeofday, as gettimeofday does
- * not return timezone information on many systems that have moved this
- * information outside of the kernel.
- */
-
-#if defined(HAVE_TIMEZONE_VAR) && !defined (TCL_GOT_TIMEZONE)
+#if defined(HAVE_TIMEZONE_VAR) && !defined(TCL_GOT_TIMEZONE) && !defined(USE_DELTA_FOR_TZ)
# define TCL_GOT_TIMEZONE
- static int setTZ = 0;
-#ifdef TCL_THREADS
- static Tcl_Mutex tzMutex;
-#endif
- int timeZone;
- Tcl_MutexLock(&tzMutex);
- if (!setTZ) {
- tzset();
- setTZ = 1;
- }
- Tcl_MutexUnlock(&tzMutex);
+ int timeZone;
+
+ /* The 'timezone' external var is present and may be used. */
+
+ SetTZIfNecessary();
/*
* Note: this is not a typo in "timezone" below! See tzset
@@ -209,30 +193,36 @@ TclpGetTimeZone (currentTime)
*/
timeZone = timezone / 60;
-
return timeZone;
+
#endif
-#if !defined(NO_GETTOD) && !defined (TCL_GOT_TIMEZONE)
-# define TCL_GOT_TIMEZONE
- struct timeval tv;
- struct timezone tz;
- int timeZone;
+#if !defined(TCL_GOT_TIMEZONE)
+#define TCL_GOT_TIMEZONE 1
+ /*
+ * Fallback - determine time zone with a known reference time.
+ */
- gettimeofday(&tv, &tz);
- timeZone = tz.tz_minuteswest;
- if (tz.tz_dsttime) {
- timeZone += 60;
+ int timeZone;
+ 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;
}
-
- return timeZone;
+ 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.
+
+#error autoconf did not figure out how to determine the timezone.
+
#endif
}
@@ -290,9 +280,9 @@ TclpGetDate(time, useGMT)
int useGMT;
{
if (useGMT) {
- return ThreadSafeGMTime(time);
+ return TclpGmtime(time);
} else {
- return ThreadSafeLocalTime(time);
+ return TclpLocaltime(time);
}
}
@@ -354,7 +344,7 @@ TclpStrftime(s, maxsize, format, t, useGMT)
/*
*----------------------------------------------------------------------
*
- * ThreadSafeGMTime --
+ * TclpGmtime --
*
* Wrapper around the 'gmtime' library function to make it thread
* safe.
@@ -368,33 +358,42 @@ TclpStrftime(s, maxsize, format, t, useGMT)
*----------------------------------------------------------------------
*/
-static struct tm *
-ThreadSafeGMTime(timePtr)
+struct tm *
+TclpGmtime( timePtr )
CONST time_t *timePtr; /* Pointer to the number of seconds
- * since the local system's epoch
- */
+ * since the local system's epoch */
{
/*
* Get a thread-local buffer to hold the returned time.
*/
- struct tm *tmPtr = (struct tm *)
- Tcl_GetThreadData(&tmKey, sizeof(struct tm));
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT( &tmKey );
#ifdef HAVE_GMTIME_R
- gmtime_r(timePtr, tmPtr);
+ gmtime_r(timePtr, &( tsdPtr->gmtime_buf ));
#else
- Tcl_MutexLock(&tmMutex);
- memcpy((VOID *) tmPtr, (VOID *) gmtime(timePtr), sizeof(struct tm));
- Tcl_MutexUnlock(&tmMutex);
+ Tcl_MutexLock( &tmMutex );
+ memcpy( (VOID *) &( tsdPtr->gmtime_buf ),
+ (VOID *) gmtime( timePtr ),
+ sizeof( struct tm ) );
+ Tcl_MutexUnlock( &tmMutex );
#endif
- return tmPtr;
+ return &( tsdPtr->gmtime_buf );
+}
+/*
+ * Forwarder for obsolete item in Stubs
+ */
+struct tm*
+TclpGmtime_unix( timePtr )
+ CONST time_t* timePtr;
+{
+ return TclpGmtime( timePtr );
}
/*
*----------------------------------------------------------------------
*
- * ThreadSafeLocalTime --
+ * TclpLocaltime --
*
* Wrapper around the 'localtime' library function to make it thread
* safe.
@@ -408,25 +407,99 @@ ThreadSafeGMTime(timePtr)
*----------------------------------------------------------------------
*/
-static struct tm *
-ThreadSafeLocalTime(timePtr)
+struct tm *
+TclpLocaltime(timePtr)
CONST time_t *timePtr; /* Pointer to the number of seconds
- * since the local system's epoch
- */
+ * since the local system's epoch */
{
/*
* Get a thread-local buffer to hold the returned time.
*/
- struct tm *tmPtr = (struct tm *)
- Tcl_GetThreadData(&tmKey, sizeof(struct tm));
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT( &tmKey );
+ SetTZIfNecessary();
#ifdef HAVE_LOCALTIME_R
- localtime_r(timePtr, tmPtr);
+ 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 )
+ CONST time_t* 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);
- memcpy((VOID *) tmPtr, (VOID *) localtime(timePtr), sizeof(struct tm));
+ if ( newTZ == NULL ) {
+ newTZ = "";
+ }
+ if ( lastTZ == NULL || strcmp( lastTZ, newTZ ) ) {
+ tzset();
+ if ( lastTZ == NULL ) {
+ Tcl_CreateExitHandler( CleanupMemory, (ClientData) NULL );
+ } else {
+ Tcl_Free( lastTZ );
+ }
+ lastTZ = Tcl_Alloc( strlen( newTZ ) + 1 );
+ strcpy( lastTZ, newTZ );
+ }
Tcl_MutexUnlock(&tmMutex);
-#endif
- return tmPtr;
+
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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 )
+{
+ Tcl_Free( lastTZ );
}
diff --git a/win/tclWinTime.c b/win/tclWinTime.c
index 2c10978..38523b2 100644
--- a/win/tclWinTime.c
+++ b/win/tclWinTime.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinTime.c,v 1.25 2004/04/23 07:12:08 davygrvy Exp $
+ * RCS: @(#) $Id: tclWinTime.c,v 1.26 2004/05/14 21:43:29 kennykb Exp $
*/
#include "tclInt.h"
@@ -578,7 +578,7 @@ TclpGetDate(t, useGMT)
#else
if (*t >= 0) {
#endif
- return localtime(t);
+ return TclpLocaltime(t);
}
time = *t - timezone;
@@ -1084,3 +1084,65 @@ AccumulateSample( Tcl_WideInt perfCounter,
return estFreq;
}
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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( timePtr )
+ CONST time_t *timePtr; /* Pointer to the number of seconds
+ * since the local system's epoch */
+
+{
+ /*
+ * The MS implementation of gmtime is thread safe because
+ * it returns the time in a block of thread-local storage,
+ * and Windows does not provide a Posix gmtime_r function.
+ */
+ return gmtime( 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( timePtr )
+ CONST time_t *timePtr; /* Pointer to the number of seconds
+ * since the local system's epoch */
+
+{
+ /*
+ * The MS implementation of localtime is thread safe because
+ * it returns the time in a block of thread-local storage,
+ * and Windows does not provide a Posix localtime_r function.
+ */
+ return localtime( timePtr );
+}