1 |
dashley |
25 |
/* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tcl_base/tclwintime.c,v 1.1.1.1 2001/06/13 04:50:48 dtashley Exp $ */
|
2 |
|
|
|
3 |
|
|
/*
|
4 |
|
|
* tclWinTime.c --
|
5 |
|
|
*
|
6 |
|
|
* Contains Windows specific versions of Tcl functions that
|
7 |
|
|
* obtain time values from the operating system.
|
8 |
|
|
*
|
9 |
|
|
* Copyright 1995-1998 by Sun Microsystems, Inc.
|
10 |
|
|
*
|
11 |
|
|
* See the file "license.terms" for information on usage and redistribution
|
12 |
|
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
13 |
|
|
*
|
14 |
|
|
* RCS: @(#) $Id: tclwintime.c,v 1.1.1.1 2001/06/13 04:50:48 dtashley Exp $
|
15 |
|
|
*/
|
16 |
|
|
|
17 |
|
|
#include "tclWinInt.h"
|
18 |
|
|
|
19 |
|
|
#define SECSPERDAY (60L * 60L * 24L)
|
20 |
|
|
#define SECSPERYEAR (SECSPERDAY * 365L)
|
21 |
|
|
#define SECSPER4YEAR (SECSPERYEAR * 4L + SECSPERDAY)
|
22 |
|
|
|
23 |
|
|
/*
|
24 |
|
|
* The following arrays contain the day of year for the last day of
|
25 |
|
|
* each month, where index 1 is January.
|
26 |
|
|
*/
|
27 |
|
|
|
28 |
|
|
static int normalDays[] = {
|
29 |
|
|
-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
|
30 |
|
|
};
|
31 |
|
|
|
32 |
|
|
static int leapDays[] = {
|
33 |
|
|
-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
|
34 |
|
|
};
|
35 |
|
|
|
36 |
|
|
typedef struct ThreadSpecificData {
|
37 |
|
|
char tzName[64]; /* Time zone name */
|
38 |
|
|
struct tm tm; /* time information */
|
39 |
|
|
} ThreadSpecificData;
|
40 |
|
|
static Tcl_ThreadDataKey dataKey;
|
41 |
|
|
|
42 |
|
|
/*
|
43 |
|
|
* Declarations for functions defined later in this file.
|
44 |
|
|
*/
|
45 |
|
|
|
46 |
|
|
static struct tm * ComputeGMT _ANSI_ARGS_((const time_t *tp));
|
47 |
|
|
|
48 |
|
|
/*
|
49 |
|
|
*----------------------------------------------------------------------
|
50 |
|
|
*
|
51 |
|
|
* TclpGetSeconds --
|
52 |
|
|
*
|
53 |
|
|
* This procedure returns the number of seconds from the epoch.
|
54 |
|
|
* On most Unix systems the epoch is Midnight Jan 1, 1970 GMT.
|
55 |
|
|
*
|
56 |
|
|
* Results:
|
57 |
|
|
* Number of seconds from the epoch.
|
58 |
|
|
*
|
59 |
|
|
* Side effects:
|
60 |
|
|
* None.
|
61 |
|
|
*
|
62 |
|
|
*----------------------------------------------------------------------
|
63 |
|
|
*/
|
64 |
|
|
|
65 |
|
|
unsigned long
|
66 |
|
|
TclpGetSeconds()
|
67 |
|
|
{
|
68 |
|
|
return (unsigned long) time((time_t *) NULL);
|
69 |
|
|
}
|
70 |
|
|
|
71 |
|
|
/*
|
72 |
|
|
*----------------------------------------------------------------------
|
73 |
|
|
*
|
74 |
|
|
* TclpGetClicks --
|
75 |
|
|
*
|
76 |
|
|
* This procedure returns a value that represents the highest
|
77 |
|
|
* resolution clock available on the system. There are no
|
78 |
|
|
* guarantees on what the resolution will be. In Tcl we will
|
79 |
|
|
* call this value a "click". The start time is also system
|
80 |
|
|
* dependant.
|
81 |
|
|
*
|
82 |
|
|
* Results:
|
83 |
|
|
* Number of clicks from some start time.
|
84 |
|
|
*
|
85 |
|
|
* Side effects:
|
86 |
|
|
* None.
|
87 |
|
|
*
|
88 |
|
|
*----------------------------------------------------------------------
|
89 |
|
|
*/
|
90 |
|
|
|
91 |
|
|
unsigned long
|
92 |
|
|
TclpGetClicks()
|
93 |
|
|
{
|
94 |
|
|
return GetTickCount();
|
95 |
|
|
}
|
96 |
|
|
|
97 |
|
|
/*
|
98 |
|
|
*----------------------------------------------------------------------
|
99 |
|
|
*
|
100 |
|
|
* TclpGetTimeZone --
|
101 |
|
|
*
|
102 |
|
|
* Determines the current timezone. The method varies wildly
|
103 |
|
|
* between different Platform implementations, so its hidden in
|
104 |
|
|
* this function.
|
105 |
|
|
*
|
106 |
|
|
* Results:
|
107 |
|
|
* Minutes west of GMT.
|
108 |
|
|
*
|
109 |
|
|
* Side effects:
|
110 |
|
|
* None.
|
111 |
|
|
*
|
112 |
|
|
*----------------------------------------------------------------------
|
113 |
|
|
*/
|
114 |
|
|
|
115 |
|
|
int
|
116 |
|
|
TclpGetTimeZone (currentTime)
|
117 |
|
|
unsigned long currentTime;
|
118 |
|
|
{
|
119 |
|
|
int timeZone;
|
120 |
|
|
|
121 |
|
|
tzset();
|
122 |
|
|
timeZone = _timezone / 60;
|
123 |
|
|
|
124 |
|
|
return timeZone;
|
125 |
|
|
}
|
126 |
|
|
|
127 |
|
|
/*
|
128 |
|
|
*----------------------------------------------------------------------
|
129 |
|
|
*
|
130 |
|
|
* TclpGetTime --
|
131 |
|
|
*
|
132 |
|
|
* Gets the current system time in seconds and microseconds
|
133 |
|
|
* since the beginning of the epoch: 00:00 UCT, January 1, 1970.
|
134 |
|
|
*
|
135 |
|
|
* Results:
|
136 |
|
|
* Returns the current time in timePtr.
|
137 |
|
|
*
|
138 |
|
|
* Side effects:
|
139 |
|
|
* None.
|
140 |
|
|
*
|
141 |
|
|
*----------------------------------------------------------------------
|
142 |
|
|
*/
|
143 |
|
|
|
144 |
|
|
void
|
145 |
|
|
TclpGetTime(timePtr)
|
146 |
|
|
Tcl_Time *timePtr; /* Location to store time information. */
|
147 |
|
|
{
|
148 |
|
|
struct timeb t;
|
149 |
|
|
|
150 |
|
|
ftime(&t);
|
151 |
|
|
timePtr->sec = t.time;
|
152 |
|
|
timePtr->usec = t.millitm * 1000;
|
153 |
|
|
}
|
154 |
|
|
|
155 |
|
|
/*
|
156 |
|
|
*----------------------------------------------------------------------
|
157 |
|
|
*
|
158 |
|
|
* TclpGetTZName --
|
159 |
|
|
*
|
160 |
|
|
* Gets the current timezone string.
|
161 |
|
|
*
|
162 |
|
|
* Results:
|
163 |
|
|
* Returns a pointer to a static string, or NULL on failure.
|
164 |
|
|
*
|
165 |
|
|
* Side effects:
|
166 |
|
|
* None.
|
167 |
|
|
*
|
168 |
|
|
*----------------------------------------------------------------------
|
169 |
|
|
*/
|
170 |
|
|
|
171 |
|
|
char *
|
172 |
|
|
TclpGetTZName(int dst)
|
173 |
|
|
{
|
174 |
|
|
int len;
|
175 |
|
|
char *zone, *p;
|
176 |
|
|
TIME_ZONE_INFORMATION tz;
|
177 |
|
|
Tcl_Encoding encoding;
|
178 |
|
|
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
179 |
|
|
char *name = tsdPtr->tzName;
|
180 |
|
|
|
181 |
|
|
/*
|
182 |
|
|
* tzset() under Borland doesn't seem to set up tzname[] at all.
|
183 |
|
|
* tzset() under MSVC has the following weird observed behavior:
|
184 |
|
|
* First time we call "clock format [clock seconds] -format %Z -gmt 1"
|
185 |
|
|
* we get "GMT", but on all subsequent calls we get the current time
|
186 |
|
|
* zone string, even though env(TZ) is GMT and the variable _timezone
|
187 |
|
|
* is 0.
|
188 |
|
|
*/
|
189 |
|
|
|
190 |
|
|
name[0] = '\0';
|
191 |
|
|
|
192 |
|
|
zone = getenv("TZ");
|
193 |
|
|
if (zone != NULL) {
|
194 |
|
|
/*
|
195 |
|
|
* TZ is of form "NST-4:30NDT", where "NST" would be the
|
196 |
|
|
* name of the standard time zone for this area, "-4:30" is
|
197 |
|
|
* the offset from GMT in hours, and "NDT is the name of
|
198 |
|
|
* the daylight savings time zone in this area. The offset
|
199 |
|
|
* and DST strings are optional.
|
200 |
|
|
*/
|
201 |
|
|
|
202 |
|
|
len = strlen(zone);
|
203 |
|
|
if (len > 3) {
|
204 |
|
|
len = 3;
|
205 |
|
|
}
|
206 |
|
|
if (dst != 0) {
|
207 |
|
|
/*
|
208 |
|
|
* Skip the offset string and get the DST string.
|
209 |
|
|
*/
|
210 |
|
|
|
211 |
|
|
p = zone + len;
|
212 |
|
|
p += strspn(p, "+-:0123456789");
|
213 |
|
|
if (*p != '\0') {
|
214 |
|
|
zone = p;
|
215 |
|
|
len = strlen(zone);
|
216 |
|
|
if (len > 3) {
|
217 |
|
|
len = 3;
|
218 |
|
|
}
|
219 |
|
|
}
|
220 |
|
|
}
|
221 |
|
|
Tcl_ExternalToUtf(NULL, NULL, zone, len, 0, NULL, name,
|
222 |
|
|
sizeof(tsdPtr->tzName), NULL, NULL, NULL);
|
223 |
|
|
}
|
224 |
|
|
if (name[0] == '\0') {
|
225 |
|
|
if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_UNKNOWN) {
|
226 |
|
|
/*
|
227 |
|
|
* MSDN: On NT this is returned if DST is not used in
|
228 |
|
|
* the current TZ
|
229 |
|
|
*/
|
230 |
|
|
dst = 0;
|
231 |
|
|
}
|
232 |
|
|
encoding = Tcl_GetEncoding(NULL, "unicode");
|
233 |
|
|
Tcl_ExternalToUtf(NULL, encoding,
|
234 |
|
|
(char *) ((dst) ? tz.DaylightName : tz.StandardName), -1,
|
235 |
|
|
0, NULL, name, sizeof(tsdPtr->tzName), NULL, NULL, NULL);
|
236 |
|
|
Tcl_FreeEncoding(encoding);
|
237 |
|
|
}
|
238 |
|
|
return name;
|
239 |
|
|
}
|
240 |
|
|
|
241 |
|
|
/*
|
242 |
|
|
*----------------------------------------------------------------------
|
243 |
|
|
*
|
244 |
|
|
* TclpGetDate --
|
245 |
|
|
*
|
246 |
|
|
* This function converts between seconds and struct tm. If
|
247 |
|
|
* useGMT is true, then the returned date will be in Greenwich
|
248 |
|
|
* Mean Time (GMT). Otherwise, it will be in the local time zone.
|
249 |
|
|
*
|
250 |
|
|
* Results:
|
251 |
|
|
* Returns a static tm structure.
|
252 |
|
|
*
|
253 |
|
|
* Side effects:
|
254 |
|
|
* None.
|
255 |
|
|
*
|
256 |
|
|
*----------------------------------------------------------------------
|
257 |
|
|
*/
|
258 |
|
|
|
259 |
|
|
struct tm *
|
260 |
|
|
TclpGetDate(t, useGMT)
|
261 |
|
|
TclpTime_t t;
|
262 |
|
|
int useGMT;
|
263 |
|
|
{
|
264 |
|
|
const time_t *tp = (const time_t *) t;
|
265 |
|
|
struct tm *tmPtr;
|
266 |
|
|
long time;
|
267 |
|
|
|
268 |
|
|
if (!useGMT) {
|
269 |
|
|
tzset();
|
270 |
|
|
|
271 |
|
|
/*
|
272 |
|
|
* If we are in the valid range, let the C run-time library
|
273 |
|
|
* handle it. Otherwise we need to fake it. Note that this
|
274 |
|
|
* algorithm ignores daylight savings time before the epoch.
|
275 |
|
|
*/
|
276 |
|
|
|
277 |
|
|
if (*tp >= 0) {
|
278 |
|
|
return localtime(tp);
|
279 |
|
|
}
|
280 |
|
|
|
281 |
|
|
time = *tp - _timezone;
|
282 |
|
|
|
283 |
|
|
/*
|
284 |
|
|
* If we aren't near to overflowing the long, just add the bias and
|
285 |
|
|
* use the normal calculation. Otherwise we will need to adjust
|
286 |
|
|
* the result at the end.
|
287 |
|
|
*/
|
288 |
|
|
|
289 |
|
|
if (*tp < (LONG_MAX - 2 * SECSPERDAY)
|
290 |
|
|
&& *tp > (LONG_MIN + 2 * SECSPERDAY)) {
|
291 |
|
|
tmPtr = ComputeGMT(&time);
|
292 |
|
|
} else {
|
293 |
|
|
tmPtr = ComputeGMT(tp);
|
294 |
|
|
|
295 |
|
|
tzset();
|
296 |
|
|
|
297 |
|
|
/*
|
298 |
|
|
* Add the bias directly to the tm structure to avoid overflow.
|
299 |
|
|
* Propagate seconds overflow into minutes, hours and days.
|
300 |
|
|
*/
|
301 |
|
|
|
302 |
|
|
time = tmPtr->tm_sec - _timezone;
|
303 |
|
|
tmPtr->tm_sec = (int)(time % 60);
|
304 |
|
|
if (tmPtr->tm_sec < 0) {
|
305 |
|
|
tmPtr->tm_sec += 60;
|
306 |
|
|
time -= 60;
|
307 |
|
|
}
|
308 |
|
|
|
309 |
|
|
time = tmPtr->tm_min + time/60;
|
310 |
|
|
tmPtr->tm_min = (int)(time % 60);
|
311 |
|
|
if (tmPtr->tm_min < 0) {
|
312 |
|
|
tmPtr->tm_min += 60;
|
313 |
|
|
time -= 60;
|
314 |
|
|
}
|
315 |
|
|
|
316 |
|
|
time = tmPtr->tm_hour + time/60;
|
317 |
|
|
tmPtr->tm_hour = (int)(time % 24);
|
318 |
|
|
if (tmPtr->tm_hour < 0) {
|
319 |
|
|
tmPtr->tm_hour += 24;
|
320 |
|
|
time -= 24;
|
321 |
|
|
}
|
322 |
|
|
|
323 |
|
|
time /= 24;
|
324 |
|
|
tmPtr->tm_mday += time;
|
325 |
|
|
tmPtr->tm_yday += time;
|
326 |
|
|
tmPtr->tm_wday = (tmPtr->tm_wday + time) % 7;
|
327 |
|
|
}
|
328 |
|
|
} else {
|
329 |
|
|
tmPtr = ComputeGMT(tp);
|
330 |
|
|
}
|
331 |
|
|
return tmPtr;
|
332 |
|
|
}
|
333 |
|
|
|
334 |
|
|
/*
|
335 |
|
|
*----------------------------------------------------------------------
|
336 |
|
|
*
|
337 |
|
|
* ComputeGMT --
|
338 |
|
|
*
|
339 |
|
|
* This function computes GMT given the number of seconds since
|
340 |
|
|
* the epoch (midnight Jan 1 1970).
|
341 |
|
|
*
|
342 |
|
|
* Results:
|
343 |
|
|
* Returns a (per thread) statically allocated struct tm.
|
344 |
|
|
*
|
345 |
|
|
* Side effects:
|
346 |
|
|
* Updates the values of the static struct tm.
|
347 |
|
|
*
|
348 |
|
|
*----------------------------------------------------------------------
|
349 |
|
|
*/
|
350 |
|
|
|
351 |
|
|
static struct tm *
|
352 |
|
|
ComputeGMT(tp)
|
353 |
|
|
const time_t *tp;
|
354 |
|
|
{
|
355 |
|
|
struct tm *tmPtr;
|
356 |
|
|
long tmp, rem;
|
357 |
|
|
int isLeap;
|
358 |
|
|
int *days;
|
359 |
|
|
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
360 |
|
|
|
361 |
|
|
tmPtr = &tsdPtr->tm;
|
362 |
|
|
|
363 |
|
|
/*
|
364 |
|
|
* Compute the 4 year span containing the specified time.
|
365 |
|
|
*/
|
366 |
|
|
|
367 |
|
|
tmp = *tp / SECSPER4YEAR;
|
368 |
|
|
rem = *tp % SECSPER4YEAR;
|
369 |
|
|
|
370 |
|
|
/*
|
371 |
|
|
* Correct for weird mod semantics so the remainder is always positive.
|
372 |
|
|
*/
|
373 |
|
|
|
374 |
|
|
if (rem < 0) {
|
375 |
|
|
tmp--;
|
376 |
|
|
rem += SECSPER4YEAR;
|
377 |
|
|
}
|
378 |
|
|
|
379 |
|
|
/*
|
380 |
|
|
* Compute the year after 1900 by taking the 4 year span and adjusting
|
381 |
|
|
* for the remainder. This works because 2000 is a leap year, and
|
382 |
|
|
* 1900/2100 are out of the range.
|
383 |
|
|
*/
|
384 |
|
|
|
385 |
|
|
tmp = (tmp * 4) + 70;
|
386 |
|
|
isLeap = 0;
|
387 |
|
|
if (rem >= SECSPERYEAR) { /* 1971, etc. */
|
388 |
|
|
tmp++;
|
389 |
|
|
rem -= SECSPERYEAR;
|
390 |
|
|
if (rem >= SECSPERYEAR) { /* 1972, etc. */
|
391 |
|
|
tmp++;
|
392 |
|
|
rem -= SECSPERYEAR;
|
393 |
|
|
if (rem >= SECSPERYEAR + SECSPERDAY) { /* 1973, etc. */
|
394 |
|
|
tmp++;
|
395 |
|
|
rem -= SECSPERYEAR + SECSPERDAY;
|
396 |
|
|
} else {
|
397 |
|
|
isLeap = 1;
|
398 |
|
|
}
|
399 |
|
|
}
|
400 |
|
|
}
|
401 |
|
|
tmPtr->tm_year = tmp;
|
402 |
|
|
|
403 |
|
|
/*
|
404 |
|
|
* Compute the day of year and leave the seconds in the current day in
|
405 |
|
|
* the remainder.
|
406 |
|
|
*/
|
407 |
|
|
|
408 |
|
|
tmPtr->tm_yday = rem / SECSPERDAY;
|
409 |
|
|
rem %= SECSPERDAY;
|
410 |
|
|
|
411 |
|
|
/*
|
412 |
|
|
* Compute the time of day.
|
413 |
|
|
*/
|
414 |
|
|
|
415 |
|
|
tmPtr->tm_hour = rem / 3600;
|
416 |
|
|
rem %= 3600;
|
417 |
|
|
tmPtr->tm_min = rem / 60;
|
418 |
|
|
tmPtr->tm_sec = rem % 60;
|
419 |
|
|
|
420 |
|
|
/*
|
421 |
|
|
* Compute the month and day of month.
|
422 |
|
|
*/
|
423 |
|
|
|
424 |
|
|
days = (isLeap) ? leapDays : normalDays;
|
425 |
|
|
for (tmp = 1; days[tmp] < tmPtr->tm_yday; tmp++) {
|
426 |
|
|
}
|
427 |
|
|
tmPtr->tm_mon = --tmp;
|
428 |
|
|
tmPtr->tm_mday = tmPtr->tm_yday - days[tmp];
|
429 |
|
|
|
430 |
|
|
/*
|
431 |
|
|
* Compute day of week. Epoch started on a Thursday.
|
432 |
|
|
*/
|
433 |
|
|
|
434 |
|
|
tmPtr->tm_wday = (*tp / SECSPERDAY) + 4;
|
435 |
|
|
if ((*tp % SECSPERDAY) < 0) {
|
436 |
|
|
tmPtr->tm_wday--;
|
437 |
|
|
}
|
438 |
|
|
tmPtr->tm_wday %= 7;
|
439 |
|
|
if (tmPtr->tm_wday < 0) {
|
440 |
|
|
tmPtr->tm_wday += 7;
|
441 |
|
|
}
|
442 |
|
|
|
443 |
|
|
return tmPtr;
|
444 |
|
|
}
|
445 |
|
|
|
446 |
|
|
|
447 |
|
|
/* $History: tclwintime.c $
|
448 |
|
|
*
|
449 |
|
|
* ***************** Version 1 *****************
|
450 |
|
|
* User: Dtashley Date: 1/02/01 Time: 12:20a
|
451 |
|
|
* Created in $/IjuScripter, IjuConsole/Source/Tcl Base
|
452 |
|
|
* Initial check-in.
|
453 |
|
|
*/
|
454 |
|
|
|
455 |
|
|
/* End of TCLWINTIME.C */ |