summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixTime.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixTime.c')
-rw-r--r--unix/tclUnixTime.c283
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: