summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixTime.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixTime.c')
-rw-r--r--unix/tclUnixTime.c425
1 files changed, 180 insertions, 245 deletions
diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c
index c7921fe..707dfbc 100644
--- a/unix/tclUnixTime.c
+++ b/unix/tclUnixTime.c
@@ -11,11 +11,8 @@
*/
#include "tclInt.h"
+#include "tclPort.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))
@@ -46,20 +43,8 @@ static char *lastTZ = NULL; /* Holds the last setting of the TZ
* Static functions declared in this file.
*/
-static void SetTZIfNecessary(void);
-static void CleanupMemory(ClientData clientData);
-static void NativeScaleTime(Tcl_Time *timebuf,
- ClientData clientData);
-static void NativeGetTime(Tcl_Time *timebuf,
- ClientData clientData);
-
-/*
- * TIP #233 (Virtualized Time): Data for the time hooks, if any.
- */
-
-Tcl_GetTimeProc *tclGetTimeProcPtr = NativeGetTime;
-Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime;
-ClientData tclTimeClientData = NULL;
+static void SetTZIfNecessary _ANSI_ARGS_((void));
+static void CleanupMemory _ANSI_ARGS_((ClientData));
/*
*----------------------------------------------------------------------
@@ -79,9 +64,9 @@ ClientData tclTimeClientData = NULL;
*/
unsigned long
-TclpGetSeconds(void)
+TclpGetSeconds()
{
- return time(NULL);
+ return time((time_t *) NULL);
}
/*
@@ -104,47 +89,37 @@ TclpGetSeconds(void)
*/
unsigned long
-TclpGetClicks(void)
+TclpGetClicks()
{
unsigned long now;
#ifdef NO_GETTOD
- if (tclGetTimeProcPtr != NativeGetTime) {
- Tcl_Time time;
-
- tclGetTimeProcPtr(&time, tclTimeClientData);
- now = time.sec*1000000 + time.usec;
- } else {
- /*
- * A semi-NativeGetTime, specialized to clicks.
- */
- struct tms dummy;
-
- now = (unsigned long) times(&dummy);
- }
+ struct tms dummy;
#else
- Tcl_Time time;
+ struct timeval date;
+#endif
- tclGetTimeProcPtr(&time, tclTimeClientData);
- now = time.sec*1000000 + time.usec;
+#ifdef NO_GETTOD
+ now = (unsigned long) times(&dummy);
+#else
+ gettimeofday(&date, NULL);
+ now = date.tv_sec*1000000 + date.tv_usec;
#endif
return now;
}
-#ifdef TCL_WIDE_CLICKS
/*
*----------------------------------------------------------------------
*
- * TclpGetWideClicks --
+ * TclpGetTimeZone --
*
- * This procedure returns a WideInt 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.
+ * Determines the current timezone. The method varies wildly between
+ * different platform implementations, so its hidden in this function.
*
* Results:
- * Number of WideInt clicks from some start time.
+ * The return value is the local time zone, measured in minutes away from
+ * GMT (-ve for east, +ve for west).
*
* Side effects:
* None.
@@ -152,74 +127,103 @@ TclpGetClicks(void)
*----------------------------------------------------------------------
*/
-Tcl_WideInt
-TclpGetWideClicks(void)
+int
+TclpGetTimeZone(currentTime)
+ Tcl_WideInt currentTime;
{
- Tcl_WideInt now;
+ int timeZone;
- if (tclGetTimeProcPtr != NativeGetTime) {
- Tcl_Time time;
+ /*
+ * 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.
+ */
- tclGetTimeProcPtr(&time, tclTimeClientData);
- now = (Tcl_WideInt) (time.sec*1000000 + time.usec);
- } else {
-#ifdef MAC_OSX_TCL
- now = (Tcl_WideInt) (mach_absolute_time() & INT64_MAX);
-#else
-#error Wide high-resolution clicks not implemented on this platform
+#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);
+
+ 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((TclpTime_t) &curTime);
+
+ timeZone = -(timeDataPtr->tm_gmtoff / 60);
+ if (timeDataPtr->tm_isdst) {
+ timeZone += 60;
}
+#endif
- return now;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpWideClicksToNanoseconds --
- *
- * This procedure converts click values from the TclpGetWideClicks native
- * resolution to nanosecond resolution.
- *
- * Results:
- * Number of nanoseconds from some start time.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
+#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.
+ */
-double
-TclpWideClicksToNanoseconds(
- Tcl_WideInt clicks)
-{
- double nsec;
+ SetTZIfNecessary();
- 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;
- }
- if ((uint64_t) clicks < maxClicksForUInt64) {
- nsec = ((uint64_t) clicks) * tb.numer / tb.denom;
- } else {
- nsec = ((long double) (uint64_t) clicks) * tb.numer / tb.denom;
- }
-#else
-#error Wide high-resolution clicks not implemented on this platform
+ /*
+ * 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((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 nsec;
+ /*
+ * 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 */
/*
*----------------------------------------------------------------------
@@ -229,9 +233,6 @@ TclpWideClicksToNanoseconds(
* Gets the current system time in seconds and microseconds since the
* beginning of the epoch: 00:00 UCT, January 1, 1970.
*
- * This function is hooked, allowing users to specify their own virtual
- * system time.
- *
* Results:
* Returns the current time in timePtr.
*
@@ -242,10 +243,14 @@ TclpWideClicksToNanoseconds(
*/
void
-Tcl_GetTime(
- Tcl_Time *timePtr) /* Location to store time information. */
+Tcl_GetTime(timePtr)
+ Tcl_Time *timePtr; /* Location to store time information. */
{
- tclGetTimeProcPtr(timePtr, tclTimeClientData);
+ struct timeval tv;
+
+ (void) gettimeofday(&tv, NULL);
+ timePtr->sec = tv.tv_sec;
+ timePtr->usec = tv.tv_usec;
}
/*
@@ -267,9 +272,9 @@ Tcl_GetTime(
*/
struct tm *
-TclpGetDate(
- const time_t *time,
- int useGMT)
+TclpGetDate(time, useGMT)
+ TclpTime_t time;
+ int useGMT;
{
if (useGMT) {
return TclpGmtime(time);
@@ -281,9 +286,48 @@ TclpGetDate(
/*
*----------------------------------------------------------------------
*
+ * 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.
+ * Wrapper around the 'gmtime' library function to make it thread
+ * safe.
*
* Results:
* Returns a pointer to a 'struct tm' in thread-specific data.
@@ -295,25 +339,28 @@ TclpGetDate(
*/
struct tm *
-TclpGmtime(
- const time_t *timePtr) /* Pointer to the number of seconds since the
- * local system's epoch */
+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);
+ gmtime_r(timePtr, &(tsdPtr->gmtime_buf));
#else
Tcl_MutexLock(&tmMutex);
- memcpy(&tsdPtr->gmtime_buf, gmtime(timePtr), sizeof(struct tm));
+ memcpy((VOID *) &(tsdPtr->gmtime_buf),
+ (VOID *) gmtime(timePtr),
+ sizeof(struct tm));
Tcl_MutexUnlock(&tmMutex);
#endif
-
- return &tsdPtr->gmtime_buf;
+ return &(tsdPtr->gmtime_buf);
}
/*
@@ -334,145 +381,33 @@ TclpGmtime(
*/
struct tm *
-TclpLocaltime(
- const time_t *timePtr) /* Pointer to the number of seconds since the
- * local system's epoch */
+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);
+ localtime_r(timePtr, &(tsdPtr->localtime_buf));
#else
Tcl_MutexLock(&tmMutex);
- memcpy(&tsdPtr->localtime_buf, localtime(timePtr), sizeof(struct tm));
+ memcpy((VOID *) &(tsdPtr -> localtime_buf),
+ (VOID *) localtime(timePtr),
+ sizeof(struct tm));
Tcl_MutexUnlock(&tmMutex);
#endif
-
- return &tsdPtr->localtime_buf;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_SetTimeProc --
- *
- * TIP #233 (Virtualized Time): Registers two handlers for the
- * virtualization of Tcl's access to time information.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Remembers the handlers, alters core behaviour.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_SetTimeProc(
- Tcl_GetTimeProc *getProc,
- Tcl_ScaleTimeProc *scaleProc,
- ClientData clientData)
-{
- tclGetTimeProcPtr = getProc;
- tclScaleTimeProcPtr = scaleProc;
- tclTimeClientData = clientData;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_QueryTimeProc --
- *
- * TIP #233 (Virtualized Time): Query which time handlers are registered.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_QueryTimeProc(
- Tcl_GetTimeProc **getProc,
- Tcl_ScaleTimeProc **scaleProc,
- ClientData *clientData)
-{
- if (getProc) {
- *getProc = tclGetTimeProcPtr;
- }
- if (scaleProc) {
- *scaleProc = tclScaleTimeProcPtr;
- }
- if (clientData) {
- *clientData = tclTimeClientData;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NativeScaleTime --
- *
- * TIP #233: Scale from virtual time to the real-time. For native scaling
- * the relationship is 1:1 and nothing has to be done.
- *
- * Results:
- * Scales the time in timePtr.
- *
- * Side effects:
- * See above.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-NativeScaleTime(
- Tcl_Time *timePtr,
- ClientData clientData)
-{
- /* Native scale is 1:1. Nothing is done */
+ return &(tsdPtr->localtime_buf);
}
/*
*----------------------------------------------------------------------
*
- * NativeGetTime --
- *
- * TIP #233: 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.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-NativeGetTime(
- Tcl_Time *timePtr,
- ClientData clientData)
-{
- struct timeval tv;
-
- (void) gettimeofday(&tv, NULL);
- timePtr->sec = tv.tv_sec;
- timePtr->usec = tv.tv_usec;
-}
-/*
- *----------------------------------------------------------------------
- *
* SetTZIfNecessary --
*
* Determines whether a call to 'tzset' is needed prior to the next call
@@ -490,9 +425,9 @@ NativeGetTime(
*/
static void
-SetTZIfNecessary(void)
+SetTZIfNecessary()
{
- const char *newTZ = getenv("TZ");
+ CONST char *newTZ = getenv("TZ");
Tcl_MutexLock(&tmMutex);
if (newTZ == NULL) {
@@ -501,7 +436,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);
}
@@ -529,8 +464,8 @@ SetTZIfNecessary(void)
*/
static void
-CleanupMemory(
- ClientData ignored)
+CleanupMemory(ignored)
+ ClientData ignored;
{
ckfree(lastTZ);
}