summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixTime.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixTime.c')
-rw-r--r--unix/tclUnixTime.c256
1 files changed, 246 insertions, 10 deletions
diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c
index 6e8c5f4..b98f2e1 100644
--- a/unix/tclUnixTime.c
+++ b/unix/tclUnixTime.c
@@ -20,6 +20,18 @@
#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.
*/
@@ -100,7 +112,7 @@ TclpGetClicks(void)
if (tclGetTimeProcPtr != NativeGetTime) {
Tcl_Time time;
- tclGetTimeProcPtr(&time, tclTimeClientData);
+ (*tclGetTimeProcPtr) (&time, tclTimeClientData);
now = time.sec*1000000 + time.usec;
} else {
/*
@@ -113,7 +125,7 @@ TclpGetClicks(void)
#else
Tcl_Time time;
- tclGetTimeProcPtr(&time, tclTimeClientData);
+ (*tclGetTimeProcPtr) (&time, tclTimeClientData);
now = time.sec*1000000 + time.usec;
#endif
@@ -122,7 +134,7 @@ TclpGetClicks(void)
#ifdef TCL_WIDE_CLICKS
/*
- *----------------------------------------------------------------------
+ *-----------------------------------------------------------------------------
*
* TclpGetWideClicks --
*
@@ -137,7 +149,7 @@ TclpGetClicks(void)
* Side effects:
* None.
*
- *----------------------------------------------------------------------
+ *-----------------------------------------------------------------------------
*/
Tcl_WideInt
@@ -148,7 +160,7 @@ TclpGetWideClicks(void)
if (tclGetTimeProcPtr != NativeGetTime) {
Tcl_Time time;
- tclGetTimeProcPtr(&time, tclTimeClientData);
+ (*tclGetTimeProcPtr) (&time, tclTimeClientData);
now = (Tcl_WideInt) (time.sec*1000000 + time.usec);
} else {
#ifdef MAC_OSX_TCL
@@ -162,7 +174,7 @@ TclpGetWideClicks(void)
}
/*
- *----------------------------------------------------------------------
+ *-----------------------------------------------------------------------------
*
* TclpWideClicksToNanoseconds --
*
@@ -175,7 +187,7 @@ TclpGetWideClicks(void)
* Side effects:
* None.
*
- *----------------------------------------------------------------------
+ *-----------------------------------------------------------------------------
*/
double
@@ -212,6 +224,122 @@ TclpWideClicksToNanoseconds(
/*
*----------------------------------------------------------------------
*
+ * 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(
+ unsigned long currentTime)
+{
+ int timeZone;
+
+ /*
+ * 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(&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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* Tcl_GetTime --
*
* Gets the current system time in seconds and microseconds since the
@@ -233,7 +361,115 @@ void
Tcl_GetTime(
Tcl_Time *timePtr) /* Location to store time information. */
{
- tclGetTimeProcPtr(timePtr, tclTimeClientData);
+ (*tclGetTimeProcPtr) (timePtr, tclTimeClientData);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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(
+ CONST time_t *time,
+ int useGMT)
+{
+ if (useGMT) {
+ return TclpGmtime(time);
+ } else {
+ return TclpLocaltime(time);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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(
+ CONST time_t *timePtr) /* 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(&(tsdPtr->gmtime_buf), gmtime(timePtr), sizeof(struct tm));
+ Tcl_MutexUnlock(&tmMutex);
+#endif
+
+ return &(tsdPtr->gmtime_buf);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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(
+ CONST time_t *timePtr) /* 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(&(tsdPtr->localtime_buf), localtime(timePtr), sizeof(struct tm));
+ Tcl_MutexUnlock(&tmMutex);
+#endif
+
+ return &(tsdPtr->localtime_buf);
}
/*
@@ -372,7 +608,7 @@ NativeGetTime(
static void
SetTZIfNecessary(void)
{
- const char *newTZ = getenv("TZ");
+ CONST char *newTZ = getenv("TZ");
Tcl_MutexLock(&tmMutex);
if (newTZ == NULL) {
@@ -381,7 +617,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);
}