blob: 90a10eb8a0d9ac48c10b2d3cb1d35703570c4ab6 [file] [log] [blame]
Guido van Rossumf70e43a1991-02-19 12:39:46 +00001/***********************************************************
Guido van Rossum524b5881995-01-04 19:10:35 +00002Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
Guido van Rossumf70e43a1991-02-19 12:39:46 +00004
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000025/* Time module */
26
Guido van Rossum3f5da241990-12-20 15:06:42 +000027#include "allobjects.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +000028#include "modsupport.h"
Guido van Rossumff4949e1992-08-05 19:58:53 +000029#include "ceval.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +000030
Guido van Rossum6d946f91992-08-14 13:49:30 +000031#ifdef macintosh
Guido van Rossumb6775db1994-08-01 11:34:53 +000032#include <time.h>
33#else
34#include <sys/types.h>
Guido van Rossum6d946f91992-08-14 13:49:30 +000035#endif
36
Guido van Rossumb6775db1994-08-01 11:34:53 +000037#ifdef QUICKWIN
38#include <io.h>
39#endif
40
41#ifdef HAVE_UNISTD_H
Guido van Rossum2762f251992-03-27 17:22:13 +000042#include <unistd.h>
43#endif
44
Guido van Rossumb6775db1994-08-01 11:34:53 +000045#ifdef HAVE_SELECT
46#include "myselect.h"
47#else
48#include "mytime.h"
49#endif
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000050
Guido van Rossumb6775db1994-08-01 11:34:53 +000051#ifdef HAVE_FTIME
52#include <sys/timeb.h>
53#endif
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000054
Guido van Rossumb6775db1994-08-01 11:34:53 +000055#ifdef _M_IX86
56#include <windows.h>
57#define timezone _timezone
Guido van Rossumb376a4a1993-11-23 17:53:17 +000058#endif
Guido van Rossum234f9421993-06-17 12:35:49 +000059
60/* Forward declarations */
Guido van Rossumb6775db1994-08-01 11:34:53 +000061static int floatsleep PROTO((double));
62static double floattime PROTO(());
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000063
64static object *
65time_time(self, args)
66 object *self;
67 object *args;
68{
Guido van Rossumb6775db1994-08-01 11:34:53 +000069 double secs;
Guido van Rossuma2b7f401993-01-04 09:09:59 +000070 if (!getnoarg(args))
71 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +000072 secs = floattime();
73 if (secs == 0.0) {
Guido van Rossuma2b7f401993-01-04 09:09:59 +000074 err_errno(IOError);
75 return NULL;
76 }
Guido van Rossumb6775db1994-08-01 11:34:53 +000077 return newfloatobject(secs);
78}
79
80#ifdef HAVE_CLOCK
81
82#ifndef CLOCKS_PER_SEC
83#define CLOCKS_PER_SEC 1000000
84#endif
85
86static object *
87time_clock(self, args)
88 object *self;
89 object *args;
90{
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000091 if (!getnoarg(args))
92 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +000093 return newfloatobject(((double)clock()) / CLOCKS_PER_SEC);
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000094}
Guido van Rossumb6775db1994-08-01 11:34:53 +000095#endif /* HAVE_CLOCK */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000096
97static object *
98time_sleep(self, args)
99 object *self;
100 object *args;
101{
Guido van Rossum775f4da1993-01-09 17:18:52 +0000102 double secs;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000103 if (!getargs(args, "d", &secs))
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000104 return NULL;
Guido van Rossumff4949e1992-08-05 19:58:53 +0000105 BGN_SAVE
Guido van Rossumb6775db1994-08-01 11:34:53 +0000106 if (floatsleep(secs) != 0) {
Guido van Rossumff4949e1992-08-05 19:58:53 +0000107 RET_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000108 return NULL;
109 }
Guido van Rossumff4949e1992-08-05 19:58:53 +0000110 END_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000111 INCREF(None);
112 return None;
113}
114
Guido van Rossum234f9421993-06-17 12:35:49 +0000115static object *
116time_convert(when, function)
117 time_t when;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000118 struct tm * (*function) PROTO((const time_t *));
Guido van Rossum234f9421993-06-17 12:35:49 +0000119{
120 struct tm *p = function(&when);
121 return mkvalue("(iiiiiiiii)",
122 p->tm_year + 1900,
123 p->tm_mon + 1, /* Want January == 1 */
124 p->tm_mday,
125 p->tm_hour,
126 p->tm_min,
127 p->tm_sec,
128 (p->tm_wday + 6) % 7, /* Want Monday == 0 */
Guido van Rossum9e90a671993-06-24 11:10:19 +0000129 p->tm_yday + 1, /* Want January, 1 == 1 */
Guido van Rossum234f9421993-06-17 12:35:49 +0000130 p->tm_isdst);
131}
132
133static object *
134time_gmtime(self, args)
135 object *self;
136 object *args;
137{
138 double when;
139 if (!getargs(args, "d", &when))
140 return NULL;
141 return time_convert((time_t)when, gmtime);
142}
143
144static object *
145time_localtime(self, args)
146 object *self;
147 object *args;
148{
149 double when;
150 if (!getargs(args, "d", &when))
151 return NULL;
152 return time_convert((time_t)when, localtime);
153}
154
Guido van Rossum9e90a671993-06-24 11:10:19 +0000155static int
156gettmarg(args, p)
157 object *args;
158 struct tm *p;
159{
160 if (!getargs(args, "(iiiiiiiii)",
161 &p->tm_year,
162 &p->tm_mon,
163 &p->tm_mday,
164 &p->tm_hour,
165 &p->tm_min,
166 &p->tm_sec,
167 &p->tm_wday,
168 &p->tm_yday,
169 &p->tm_isdst))
170 return 0;
171 if (p->tm_year >= 1900)
172 p->tm_year -= 1900;
173 p->tm_mon--;
174 p->tm_wday = (p->tm_wday + 1) % 7;
175 p->tm_yday--;
176 return 1;
177}
178
179static object *
180time_asctime(self, args)
181 object *self;
182 object *args;
183{
184 struct tm buf;
185 char *p;
186 if (!gettmarg(args, &buf))
187 return NULL;
188 p = asctime(&buf);
189 if (p[24] == '\n')
190 p[24] = '\0';
191 return newstringobject(p);
192}
193
194static object *
195time_ctime(self, args)
196 object *self;
197 object *args;
198{
199 double dt;
200 time_t tt;
201 char *p;
202 if (!getargs(args, "d", &dt))
203 return NULL;
204 tt = dt;
205 p = ctime(&tt);
206 if (p[24] == '\n')
207 p[24] = '\0';
208 return newstringobject(p);
209}
210
Guido van Rossum234f9421993-06-17 12:35:49 +0000211static object *
212time_mktime(self, args)
213 object *self;
214 object *args;
215{
216 struct tm buf;
Guido van Rossum9e90a671993-06-24 11:10:19 +0000217 if (!gettmarg(args, &buf))
Guido van Rossum234f9421993-06-17 12:35:49 +0000218 return NULL;
Guido van Rossum234f9421993-06-17 12:35:49 +0000219 return newintobject((long)mktime(&buf));
220}
221
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000222static struct methodlist time_methods[] = {
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000223 {"time", time_time},
Guido van Rossumb6775db1994-08-01 11:34:53 +0000224#ifdef HAVE_CLOCK
225 {"clock", time_clock},
226#endif
227 {"sleep", time_sleep},
Guido van Rossum234f9421993-06-17 12:35:49 +0000228 {"gmtime", time_gmtime},
229 {"localtime", time_localtime},
Guido van Rossum9e90a671993-06-24 11:10:19 +0000230 {"asctime", time_asctime},
231 {"ctime", time_ctime},
Guido van Rossum234f9421993-06-17 12:35:49 +0000232 {"mktime", time_mktime},
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000233 {NULL, NULL} /* sentinel */
234};
235
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000236static void
237ins(d, name, v)
238 object *d;
239 char *name;
240 object *v;
241{
242 if (v == NULL)
243 fatal("Can't initialize time module -- NULL value");
244 if (dictinsert(d, name, v) != 0)
245 fatal("Can't initialize time module -- dictinsert failed");
246 DECREF(v);
247}
248
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000249void
250inittime()
251{
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000252 object *m, *d, *v;
Guido van Rossum234f9421993-06-17 12:35:49 +0000253 m = initmodule("time", time_methods);
254 d = getmoduledict(m);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000255#ifdef HAVE_TZNAME
Guido van Rossum234f9421993-06-17 12:35:49 +0000256 tzset();
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000257 ins(d, "timezone", newintobject((long)timezone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000258#ifdef HAVE_ALTZONE
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000259 ins(d, "altzone", newintobject((long)altzone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000260#else
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000261 ins(d, "altzone", newintobject((long)timezone-3600));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000262#endif
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000263 ins(d, "daylight", newintobject((long)daylight));
264 ins(d, "tzname", mkvalue("(zz)", tzname[0], tzname[1]));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000265#else /* !HAVE_TZNAME */
266#if HAVE_TM_ZONE
Guido van Rossum234f9421993-06-17 12:35:49 +0000267 {
268#define YEAR ((time_t)((365 * 24 + 6) * 3600))
269 time_t t;
270 struct tm *p;
271 long winterzone, summerzone;
272 char wintername[10], summername[10];
Guido van Rossumb6775db1994-08-01 11:34:53 +0000273 /* XXX This won't work on the southern hemisphere.
274 XXX Anybody got a better idea? */
Guido van Rossum234f9421993-06-17 12:35:49 +0000275 t = (time((time_t *)0) / YEAR) * YEAR;
276 p = localtime(&t);
277 winterzone = -p->tm_gmtoff;
278 strncpy(wintername, p->tm_zone ? p->tm_zone : " ", 9);
279 wintername[9] = '\0';
280 t += YEAR/2;
281 p = localtime(&t);
282 summerzone = -p->tm_gmtoff;
283 strncpy(summername, p->tm_zone ? p->tm_zone : " ", 9);
284 summername[9] = '\0';
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000285 ins(d, "timezone", newintobject(winterzone));
286 ins(d, "altzone", newintobject(summerzone));
287 ins(d, "daylight", newintobject((long)(winterzone != summerzone)));
288 ins(d, "tzname", mkvalue("(zz)", wintername, summername));
Guido van Rossum234f9421993-06-17 12:35:49 +0000289 }
Guido van Rossumb6775db1994-08-01 11:34:53 +0000290#endif /* HAVE_TM_ZONE */
291#endif /* !HAVE_TZNAME */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000292}
293
294
Guido van Rossumb6775db1994-08-01 11:34:53 +0000295/* Implement floattime() for various platforms */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000296
Guido van Rossumb6775db1994-08-01 11:34:53 +0000297static double
298floattime()
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000299{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000300 /* There are three ways to get the time:
301 (1) gettimeofday() -- resolution in microseconds
302 (2) ftime() -- resolution in milliseconds
303 (3) time() -- resolution in seconds
304 In all cases the return value is a float in seconds.
305 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
306 fail, so we fall back on ftime() or time().
307 Note: clock resolution does not imply clock accuracy! */
308#ifdef HAVE_GETTIMEOFDAY
309 {
Guido van Rossum426035c1991-02-19 12:27:35 +0000310 struct timeval t;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000311#ifdef GETTIMEOFDAY_NO_TZ
312 if (gettimeofday(&t) == 0)
313 return (double)t.tv_sec + t.tv_usec*0.000001;
314#else /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000315 if (gettimeofday(&t, (struct timezone *)NULL) == 0)
316 return (double)t.tv_sec + t.tv_usec*0.000001;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000317#endif /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000318 }
319#endif /* !HAVE_GETTIMEOFDAY */
320 {
321#ifdef HAVE_FTIME
322 struct timeb t;
323 ftime(&t);
Guido van Rossum7b1e9741994-08-29 10:46:42 +0000324 return (double)t.time + (double)t.millitm * (double)0.001;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000325#else /* !HAVE_FTIME */
326 time_t secs;
327 time(&secs);
328 return (double)secs;
329#endif /* !HAVE_FTIME */
330 }
Guido van Rossum426035c1991-02-19 12:27:35 +0000331}
332
Guido van Rossumb6775db1994-08-01 11:34:53 +0000333
334/* Implement floatsleep() for various platforms.
335 When interrupted (or when another error occurs), return -1 and
336 set an exception; else return 0. */
337
338static int
Guido van Rossuma320fd31995-03-09 12:14:15 +0000339#ifdef MPW
340floatsleep(double secs)
341#else
Guido van Rossum775f4da1993-01-09 17:18:52 +0000342floatsleep(secs)
343 double secs;
Guido van Rossuma320fd31995-03-09 12:14:15 +0000344#endif /* MPW */
Guido van Rossum426035c1991-02-19 12:27:35 +0000345{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000346#ifdef HAVE_SELECT
Guido van Rossum426035c1991-02-19 12:27:35 +0000347 struct timeval t;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000348 double frac;
349 extern double fmod PROTO((double, double));
350 extern double floor PROTO((double));
351 frac = fmod(secs, 1.0);
352 secs = floor(secs);
353 t.tv_sec = (long)secs;
354 t.tv_usec = (long)(frac*1000000.0);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000355 if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
356 err_errno(IOError);
357 return -1;
358 }
359#else /* !HAVE_SELECT */
360#ifdef macintosh
361#define MacTicks (* (long *)0x16A)
362 long deadline;
363 deadline = MacTicks + (long)(secs * 60.0);
364 while (MacTicks < deadline) {
365 if (sigcheck())
366 return -1;
367 }
368#else /* !macintosh */
Guido van Rossume22e6441993-07-09 10:51:31 +0000369#ifdef MSDOS
Guido van Rossumb6775db1994-08-01 11:34:53 +0000370 struct timeb t1, t2;
371 double frac;
372 extern double fmod PROTO((double, double));
373 extern double floor PROTO((double));
374 if (secs <= 0.0)
375 return;
376 frac = fmod(secs, 1.0);
377 secs = floor(secs);
378 ftime(&t1);
379 t2.time = t1.time + (int)secs;
380 t2.millitm = t1.millitm + (int)(frac*1000.0);
381 while (t2.millitm >= 1000) {
382 t2.time++;
383 t2.millitm -= 1000;
384 }
385 for (;;) {
386#ifdef QUICKWIN
387 _wyield();
Guido van Rossum80c9d881991-04-16 08:47:51 +0000388#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000389 if (sigcheck())
390 return -1;
391 ftime(&t1);
392 if (t1.time > t2.time ||
393 t1.time == t2.time && t1.millitm >= t2.millitm)
394 break;
395 }
396#else /* !MSDOS */
397#ifdef _M_IX86
398 /* XXX Can't interrupt this sleep */
399 Sleep((int)(secs*1000));
400#else /* _M_IX86 */
401 /* XXX Can't interrupt this sleep */
402 sleep((int)secs);
403#endif /* _M_IX86 */
404#endif /* !MSDOS */
405#endif /* !macintosh */
406#endif /* !HAVE_SELECT */
407 return 0;
Guido van Rossum80c9d881991-04-16 08:47:51 +0000408}