OSDN Git Service

* configure.in: Fix for autoconf 2.5.
[pf3gnuchains/pf3gnuchains3x.git] / tcl / unix / tclUnixTime.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$
13  */
14
15 #include "tclInt.h"
16 #include "tclPort.h"
17 #include <locale.h>
18 #define TM_YEAR_BASE 1900
19 #define IsLeapYear(x)   ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0))
20
21 /*
22  * TclpGetDate is coded to return a pointer to a 'struct tm'.  For
23  * thread safety, this structure must be in thread-specific data.
24  * The 'tmKey' variable is the key to this buffer.
25  */
26
27 static Tcl_ThreadDataKey tmKey;
28
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
34 #if !defined(HAVE_GMTIME_R) || !defined(HAVE_LOCALTIME_R)
35 TCL_DECLARE_MUTEX(tmMutex)
36 #endif
37
38 /*
39  * Forward declarations for procedures defined later in this file.
40  */
41
42 static struct tm *ThreadSafeGMTime _ANSI_ARGS_(( CONST time_t* ));
43 static struct tm *ThreadSafeLocalTime _ANSI_ARGS_(( CONST time_t* ));
44 \f
45 /*
46  *-----------------------------------------------------------------------------
47  *
48  * TclpGetSeconds --
49  *
50  *      This procedure returns the number of seconds from the epoch.  On
51  *      most Unix systems the epoch is Midnight Jan 1, 1970 GMT.
52  *
53  * Results:
54  *      Number of seconds from the epoch.
55  *
56  * Side effects:
57  *      None.
58  *
59  *-----------------------------------------------------------------------------
60  */
61
62 unsigned long
63 TclpGetSeconds()
64 {
65     return time((time_t *) NULL);
66 }
67 \f
68 /*
69  *-----------------------------------------------------------------------------
70  *
71  * TclpGetClicks --
72  *
73  *      This procedure returns a value that represents the highest resolution
74  *      clock available on the system.  There are no garantees on what the
75  *      resolution will be.  In Tcl we will call this value a "click".  The
76  *      start time is also system dependant.
77  *
78  * Results:
79  *      Number of clicks from some start time.
80  *
81  * Side effects:
82  *      None.
83  *
84  *-----------------------------------------------------------------------------
85  */
86
87 unsigned long
88 TclpGetClicks()
89 {
90     unsigned long now;
91 #ifdef NO_GETTOD
92     struct tms dummy;
93 #else
94     struct timeval date;
95     struct timezone tz;
96 #endif
97
98 #ifdef NO_GETTOD
99     now = (unsigned long) times(&dummy);
100 #else
101     gettimeofday(&date, &tz);
102     now = date.tv_sec*1000000 + date.tv_usec;
103 #endif
104
105     return now;
106 }
107 \f
108 /*
109  *----------------------------------------------------------------------
110  *
111  * TclpGetTimeZone --
112  *
113  *      Determines the current timezone.  The method varies wildly
114  *      between different platform implementations, so its hidden in
115  *      this function.
116  *
117  * Results:
118  *      The return value is the local time zone, measured in
119  *      minutes away from GMT (-ve for east, +ve for west).
120  *
121  * Side effects:
122  *      None.
123  *
124  *----------------------------------------------------------------------
125  */
126
127 int
128 TclpGetTimeZone (currentTime)
129     unsigned long  currentTime;
130 {
131     /*
132      * Determine how a timezone is obtained from "struct tm".  If there is no
133      * time zone in this struct (very lame) then use the timezone variable.
134      * This is done in a way to make the timezone variable the method of last
135      * resort, as some systems have it in addition to a field in "struct tm".
136      * The gettimeofday system call can also be used to determine the time
137      * zone.
138      */
139     
140 #if defined(HAVE_TM_TZADJ)
141 #   define TCL_GOT_TIMEZONE
142     time_t      curTime = (time_t) currentTime;
143     struct tm  *timeDataPtr = ThreadSafeLocalTime(&curTime);
144     int         timeZone;
145
146     timeZone = timeDataPtr->tm_tzadj  / 60;
147     if (timeDataPtr->tm_isdst) {
148         timeZone += 60;
149     }
150     
151     return timeZone;
152 #endif
153
154 #if defined(HAVE_TM_GMTOFF) && !defined (TCL_GOT_TIMEZONE)
155 #   define TCL_GOT_TIMEZONE
156     time_t     curTime = (time_t) currentTime;
157     struct tm *timeDataPtr = ThreadSafeLocalTime(&curTime);
158     int        timeZone;
159
160     timeZone = -(timeDataPtr->tm_gmtoff / 60);
161     if (timeDataPtr->tm_isdst) {
162         timeZone += 60;
163     }
164     
165     return timeZone;
166 #endif
167
168 #if defined(USE_DELTA_FOR_TZ)
169 #define TCL_GOT_TIMEZONE 1
170     /*
171      * This hack replaces using global var timezone or gettimeofday
172      * in situations where they are buggy such as on AIX when libbsd.a
173      * is linked in.
174      */
175
176     int timeZone;
177     time_t tt;
178     struct tm *stm;
179     tt = 849268800L;      /*    1996-11-29 12:00:00  GMT */
180     stm = ThreadSafeLocalTime(&tt); /* eg 1996-11-29  6:00:00  CST6CDT */
181     /* The calculation below assumes a max of +12 or -12 hours from GMT */
182     timeZone = (12 - stm->tm_hour)*60 + (0 - stm->tm_min);
183     return timeZone;  /* eg +360 for CST6CDT */
184 #endif
185
186     /*
187      * Must prefer timezone variable over gettimeofday, as gettimeofday does
188      * not return timezone information on many systems that have moved this
189      * information outside of the kernel.
190      */
191     
192 #if defined(HAVE_TIMEZONE_VAR) && !defined (TCL_GOT_TIMEZONE)
193 #   define TCL_GOT_TIMEZONE
194     static int setTZ = 0;
195 #ifdef TCL_THREADS
196     static Tcl_Mutex tzMutex;
197 #endif
198     int        timeZone;
199
200     Tcl_MutexLock(&tzMutex);
201     if (!setTZ) {
202         tzset();
203         setTZ = 1;
204     }
205     Tcl_MutexUnlock(&tzMutex);
206
207     /*
208      * Note: this is not a typo in "timezone" below!  See tzset
209      * documentation for details.
210      */
211
212     timeZone = timezone / 60;
213
214     return timeZone;
215 #endif
216
217 #if !defined(NO_GETTOD) && !defined (TCL_GOT_TIMEZONE)
218 #   define TCL_GOT_TIMEZONE
219     struct timeval  tv;
220     struct timezone tz;
221     int timeZone;
222
223     gettimeofday(&tv, &tz);
224     timeZone = tz.tz_minuteswest;
225     if (tz.tz_dsttime) {
226         timeZone += 60;
227     }
228     
229     return timeZone;
230 #endif
231
232 #ifndef TCL_GOT_TIMEZONE
233     /*
234      * Cause compile error, we don't know how to get timezone.
235      */
236     error: autoconf did not figure out how to determine the timezone. 
237 #endif
238
239 }
240 \f
241 /*
242  *----------------------------------------------------------------------
243  *
244  * Tcl_GetTime --
245  *
246  *      Gets the current system time in seconds and microseconds
247  *      since the beginning of the epoch: 00:00 UCT, January 1, 1970.
248  *
249  * Results:
250  *      Returns the current time in timePtr.
251  *
252  * Side effects:
253  *      None.
254  *
255  *----------------------------------------------------------------------
256  */
257
258 void
259 Tcl_GetTime(timePtr)
260     Tcl_Time *timePtr;          /* Location to store time information. */
261 {
262     struct timeval tv;
263     struct timezone tz;
264     
265     (void) gettimeofday(&tv, &tz);
266     timePtr->sec = tv.tv_sec;
267     timePtr->usec = tv.tv_usec;
268 }
269 \f
270 /*
271  *----------------------------------------------------------------------
272  *
273  * TclpGetDate --
274  *
275  *      This function converts between seconds and struct tm.  If
276  *      useGMT is true, then the returned date will be in Greenwich
277  *      Mean Time (GMT).  Otherwise, it will be in the local time zone.
278  *
279  * Results:
280  *      Returns a static tm structure.
281  *
282  * Side effects:
283  *      None.
284  *
285  *----------------------------------------------------------------------
286  */
287
288 struct tm *
289 TclpGetDate(time, useGMT)
290     TclpTime_t time;
291     int useGMT;
292 {
293     CONST time_t *tp = (CONST time_t *)time;
294
295     if (useGMT) {
296         return ThreadSafeGMTime(tp);
297     } else {
298         return ThreadSafeLocalTime(tp);
299     }
300 }
301 \f
302 /*
303  *----------------------------------------------------------------------
304  *
305  * TclpStrftime --
306  *
307  *      On Unix, we can safely call the native strftime implementation,
308  *      and also ignore the useGMT parameter.
309  *
310  * Results:
311  *      The normal strftime result.
312  *
313  * Side effects:
314  *      None.
315  *
316  *----------------------------------------------------------------------
317  */
318
319 size_t
320 TclpStrftime(s, maxsize, format, t, useGMT)
321     char *s;
322     size_t maxsize;
323     CONST char *format;
324     CONST struct tm *t;
325     int useGMT;
326 {
327     if (format[0] == '%' && format[1] == 'Q') {
328         /* Format as a stardate */
329         sprintf(s, "Stardate %2d%03d.%01d",
330                 (((t->tm_year + TM_YEAR_BASE) + 377) - 2323),
331                 (((t->tm_yday + 1) * 1000) /
332                         (365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))),
333                 (((t->tm_hour * 60) + t->tm_min)/144));
334         return(strlen(s));
335     }
336     setlocale(LC_TIME, "");
337     return strftime(s, maxsize, format, t);
338 }
339 \f
340 /*
341  *----------------------------------------------------------------------
342  *
343  * ThreadSafeGMTime --
344  *
345  *      Wrapper around the 'gmtime' library function to make it thread
346  *      safe.
347  *
348  * Results:
349  *      Returns a pointer to a 'struct tm' in thread-specific data.
350  *
351  * Side effects:
352  *      Invokes gmtime or gmtime_r as appropriate.
353  *
354  *----------------------------------------------------------------------
355  */
356
357 static struct tm *
358 ThreadSafeGMTime(timePtr)
359     CONST time_t *timePtr;      /* Pointer to the number of seconds
360                                  * since the local system's epoch
361                                  */
362
363 {
364     /*
365      * Get a thread-local buffer to hold the returned time.
366      */
367
368     struct tm *tmPtr = (struct tm *)
369             Tcl_GetThreadData(&tmKey, sizeof(struct tm));
370 #ifdef HAVE_GMTIME_R
371     gmtime_r(timePtr, tmPtr);
372 #else
373     Tcl_MutexLock(&tmMutex);
374     memcpy((VOID *) tmPtr, (VOID *) gmtime(timePtr), sizeof(struct tm));
375     Tcl_MutexUnlock(&tmMutex);
376 #endif    
377     return tmPtr;
378 }
379 \f
380 /*
381  *----------------------------------------------------------------------
382  *
383  * ThreadSafeLocalTime --
384  *
385  *      Wrapper around the 'localtime' library function to make it thread
386  *      safe.
387  *
388  * Results:
389  *      Returns a pointer to a 'struct tm' in thread-specific data.
390  *
391  * Side effects:
392  *      Invokes localtime or localtime_r as appropriate.
393  *
394  *----------------------------------------------------------------------
395  */
396
397 static struct tm *
398 ThreadSafeLocalTime(timePtr)
399     CONST time_t *timePtr;      /* Pointer to the number of seconds
400                                  * since the local system's epoch
401                                  */
402
403 {
404     /*
405      * Get a thread-local buffer to hold the returned time.
406      */
407
408     struct tm *tmPtr = (struct tm *)
409             Tcl_GetThreadData(&tmKey, sizeof(struct tm));
410 #ifdef HAVE_LOCALTIME_R
411     localtime_r(timePtr, tmPtr);
412 #else
413     Tcl_MutexLock(&tmMutex);
414     memcpy((VOID *) tmPtr, (VOID *) localtime(timePtr), sizeof(struct tm));
415     Tcl_MutexUnlock(&tmMutex);
416 #endif    
417     return tmPtr;
418 }