blob: 7a8c462ad5a674bd90115d092c6eace9ceeea1b3 [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 Rossum99d90c01996-08-08 19:17:45 +000031#ifdef HAVE_SELECT
32#include "mymath.h"
33#endif
34
Guido van Rossum6d946f91992-08-14 13:49:30 +000035#ifdef macintosh
Guido van Rossumb6775db1994-08-01 11:34:53 +000036#include <time.h>
37#else
38#include <sys/types.h>
Guido van Rossum6d946f91992-08-14 13:49:30 +000039#endif
40
Guido van Rossumb6775db1994-08-01 11:34:53 +000041#ifdef QUICKWIN
42#include <io.h>
43#endif
44
45#ifdef HAVE_UNISTD_H
Guido van Rossum2762f251992-03-27 17:22:13 +000046#include <unistd.h>
47#endif
48
Guido van Rossumb6775db1994-08-01 11:34:53 +000049#ifdef HAVE_SELECT
50#include "myselect.h"
51#else
52#include "mytime.h"
53#endif
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000054
Guido van Rossumb6775db1994-08-01 11:34:53 +000055#ifdef HAVE_FTIME
56#include <sys/timeb.h>
57#endif
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000058
Guido van Rossumbceeac81996-05-23 22:53:47 +000059#ifdef __WATCOMC__
60#include <i86.h>
61#else
Guido van Rossumb6775db1994-08-01 11:34:53 +000062#ifdef _M_IX86
63#include <windows.h>
64#define timezone _timezone
Guido van Rossumcc081121995-03-14 15:05:41 +000065#define tzname _tzname
66#define daylight _daylight
67#define altzone _altzone
Guido van Rossumb376a4a1993-11-23 17:53:17 +000068#endif
Guido van Rossumbceeac81996-05-23 22:53:47 +000069#endif
Guido van Rossum234f9421993-06-17 12:35:49 +000070
71/* Forward declarations */
Guido van Rossumb6775db1994-08-01 11:34:53 +000072static int floatsleep PROTO((double));
73static double floattime PROTO(());
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000074
75static object *
76time_time(self, args)
77 object *self;
78 object *args;
79{
Guido van Rossumb6775db1994-08-01 11:34:53 +000080 double secs;
Guido van Rossuma2b7f401993-01-04 09:09:59 +000081 if (!getnoarg(args))
82 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +000083 secs = floattime();
84 if (secs == 0.0) {
Guido van Rossuma2b7f401993-01-04 09:09:59 +000085 err_errno(IOError);
86 return NULL;
87 }
Guido van Rossumb6775db1994-08-01 11:34:53 +000088 return newfloatobject(secs);
89}
90
91#ifdef HAVE_CLOCK
92
93#ifndef CLOCKS_PER_SEC
Guido van Rossum1b66a4f1996-02-25 04:50:33 +000094#ifdef CLK_TCK
95#define CLOCKS_PER_SEC CLK_TCK
96#else
Guido van Rossumb6775db1994-08-01 11:34:53 +000097#define CLOCKS_PER_SEC 1000000
98#endif
Guido van Rossum1b66a4f1996-02-25 04:50:33 +000099#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000100
101static object *
102time_clock(self, args)
103 object *self;
104 object *args;
105{
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000106 if (!getnoarg(args))
107 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000108 return newfloatobject(((double)clock()) / CLOCKS_PER_SEC);
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000109}
Guido van Rossumb6775db1994-08-01 11:34:53 +0000110#endif /* HAVE_CLOCK */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000111
112static object *
113time_sleep(self, args)
114 object *self;
115 object *args;
116{
Guido van Rossum775f4da1993-01-09 17:18:52 +0000117 double secs;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000118 if (!getargs(args, "d", &secs))
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000119 return NULL;
Guido van Rossumff4949e1992-08-05 19:58:53 +0000120 BGN_SAVE
Guido van Rossumb6775db1994-08-01 11:34:53 +0000121 if (floatsleep(secs) != 0) {
Guido van Rossumff4949e1992-08-05 19:58:53 +0000122 RET_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000123 return NULL;
124 }
Guido van Rossumff4949e1992-08-05 19:58:53 +0000125 END_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000126 INCREF(None);
127 return None;
128}
129
Guido van Rossum234f9421993-06-17 12:35:49 +0000130static object *
131time_convert(when, function)
132 time_t when;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000133 struct tm * (*function) PROTO((const time_t *));
Guido van Rossum234f9421993-06-17 12:35:49 +0000134{
135 struct tm *p = function(&when);
136 return mkvalue("(iiiiiiiii)",
137 p->tm_year + 1900,
138 p->tm_mon + 1, /* Want January == 1 */
139 p->tm_mday,
140 p->tm_hour,
141 p->tm_min,
142 p->tm_sec,
143 (p->tm_wday + 6) % 7, /* Want Monday == 0 */
Guido van Rossum9e90a671993-06-24 11:10:19 +0000144 p->tm_yday + 1, /* Want January, 1 == 1 */
Guido van Rossum234f9421993-06-17 12:35:49 +0000145 p->tm_isdst);
146}
147
148static object *
149time_gmtime(self, args)
150 object *self;
151 object *args;
152{
153 double when;
154 if (!getargs(args, "d", &when))
155 return NULL;
156 return time_convert((time_t)when, gmtime);
157}
158
159static object *
160time_localtime(self, args)
161 object *self;
162 object *args;
163{
164 double when;
165 if (!getargs(args, "d", &when))
166 return NULL;
167 return time_convert((time_t)when, localtime);
168}
169
Guido van Rossum9e90a671993-06-24 11:10:19 +0000170static int
171gettmarg(args, p)
172 object *args;
173 struct tm *p;
174{
175 if (!getargs(args, "(iiiiiiiii)",
176 &p->tm_year,
177 &p->tm_mon,
178 &p->tm_mday,
179 &p->tm_hour,
180 &p->tm_min,
181 &p->tm_sec,
182 &p->tm_wday,
183 &p->tm_yday,
184 &p->tm_isdst))
185 return 0;
186 if (p->tm_year >= 1900)
187 p->tm_year -= 1900;
188 p->tm_mon--;
189 p->tm_wday = (p->tm_wday + 1) % 7;
190 p->tm_yday--;
191 return 1;
192}
193
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000194#ifdef HAVE_STRFTIME
195static object *
196time_strftime(self, args)
197 object *self;
198 object *args;
199{
200 struct tm buf;
201 const char *fmt;
202 char *outbuf = 0;
203 int i;
204
205 if (!PyArg_ParseTuple(args, "s(iiiiiiiii)",
206 &fmt,
207 &(buf.tm_year),
208 &(buf.tm_mon),
209 &(buf.tm_mday),
210 &(buf.tm_hour),
211 &(buf.tm_min),
212 &(buf.tm_sec),
213 &(buf.tm_wday),
214 &(buf.tm_yday),
215 &(buf.tm_isdst)))
216 return NULL;
217 if (buf.tm_year >= 1900)
218 buf.tm_year -= 1900;
219 buf.tm_mon--;
220 buf.tm_wday = (buf.tm_wday + 1) % 7;
221 buf.tm_yday--;
222 /* I hate these functions that presume you know how big the output */
223 /* will be ahead of time... */
224 for (i = 1024 ; i < 8192 ; i += 1024) {
225 outbuf = malloc(i);
226 if (outbuf == NULL) {
227 return err_nomem();
228 }
229 if (strftime(outbuf, i-1, fmt, &buf) != 0) {
230 object *ret;
231 ret = newstringobject(outbuf);
232 free(outbuf);
233 return ret;
234 }
235 free(outbuf);
236 }
237 return err_nomem();
238}
239#endif /* HAVE_STRFTIME */
240
Guido van Rossum9e90a671993-06-24 11:10:19 +0000241static object *
242time_asctime(self, args)
243 object *self;
244 object *args;
245{
246 struct tm buf;
247 char *p;
248 if (!gettmarg(args, &buf))
249 return NULL;
250 p = asctime(&buf);
251 if (p[24] == '\n')
252 p[24] = '\0';
253 return newstringobject(p);
254}
255
256static object *
257time_ctime(self, args)
258 object *self;
259 object *args;
260{
261 double dt;
262 time_t tt;
263 char *p;
264 if (!getargs(args, "d", &dt))
265 return NULL;
266 tt = dt;
267 p = ctime(&tt);
268 if (p[24] == '\n')
269 p[24] = '\0';
270 return newstringobject(p);
271}
272
Guido van Rossum234f9421993-06-17 12:35:49 +0000273static object *
274time_mktime(self, args)
275 object *self;
276 object *args;
277{
278 struct tm buf;
Guido van Rossumbceeac81996-05-23 22:53:47 +0000279 time_t tt;
280 tt = time(&tt);
281 buf = *localtime(&tt);
Guido van Rossum9e90a671993-06-24 11:10:19 +0000282 if (!gettmarg(args, &buf))
Guido van Rossum234f9421993-06-17 12:35:49 +0000283 return NULL;
Guido van Rossumbceeac81996-05-23 22:53:47 +0000284 tt = mktime(&buf);
285 if (tt == (time_t)(-1)) {
286 err_setstr(OverflowError, "mktime argument out of range");
287 return NULL;
288 }
289 return newfloatobject((double)tt);
Guido van Rossum234f9421993-06-17 12:35:49 +0000290}
291
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000292static struct methodlist time_methods[] = {
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000293 {"time", time_time},
Guido van Rossumb6775db1994-08-01 11:34:53 +0000294#ifdef HAVE_CLOCK
295 {"clock", time_clock},
296#endif
297 {"sleep", time_sleep},
Guido van Rossum234f9421993-06-17 12:35:49 +0000298 {"gmtime", time_gmtime},
299 {"localtime", time_localtime},
Guido van Rossum9e90a671993-06-24 11:10:19 +0000300 {"asctime", time_asctime},
301 {"ctime", time_ctime},
Guido van Rossum234f9421993-06-17 12:35:49 +0000302 {"mktime", time_mktime},
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000303#ifdef HAVE_STRFTIME
Guido van Rossum5416e201996-02-13 00:14:09 +0000304 {"strftime", time_strftime, 1},
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000305#endif
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000306 {NULL, NULL} /* sentinel */
307};
308
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000309static void
310ins(d, name, v)
311 object *d;
312 char *name;
313 object *v;
314{
315 if (v == NULL)
316 fatal("Can't initialize time module -- NULL value");
317 if (dictinsert(d, name, v) != 0)
318 fatal("Can't initialize time module -- dictinsert failed");
319 DECREF(v);
320}
321
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000322void
323inittime()
324{
Jack Jansen8ccfc931995-10-03 14:39:44 +0000325 object *m, *d;
Guido van Rossum234f9421993-06-17 12:35:49 +0000326 m = initmodule("time", time_methods);
327 d = getmoduledict(m);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000328#ifdef HAVE_TZNAME
Guido van Rossum234f9421993-06-17 12:35:49 +0000329 tzset();
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000330 ins(d, "timezone", newintobject((long)timezone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000331#ifdef HAVE_ALTZONE
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000332 ins(d, "altzone", newintobject((long)altzone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000333#else
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000334 ins(d, "altzone", newintobject((long)timezone-3600));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000335#endif
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000336 ins(d, "daylight", newintobject((long)daylight));
337 ins(d, "tzname", mkvalue("(zz)", tzname[0], tzname[1]));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000338#else /* !HAVE_TZNAME */
339#if HAVE_TM_ZONE
Guido van Rossum234f9421993-06-17 12:35:49 +0000340 {
341#define YEAR ((time_t)((365 * 24 + 6) * 3600))
342 time_t t;
343 struct tm *p;
344 long winterzone, summerzone;
345 char wintername[10], summername[10];
Guido van Rossumb6775db1994-08-01 11:34:53 +0000346 /* XXX This won't work on the southern hemisphere.
347 XXX Anybody got a better idea? */
Guido van Rossum234f9421993-06-17 12:35:49 +0000348 t = (time((time_t *)0) / YEAR) * YEAR;
349 p = localtime(&t);
350 winterzone = -p->tm_gmtoff;
351 strncpy(wintername, p->tm_zone ? p->tm_zone : " ", 9);
352 wintername[9] = '\0';
353 t += YEAR/2;
354 p = localtime(&t);
355 summerzone = -p->tm_gmtoff;
356 strncpy(summername, p->tm_zone ? p->tm_zone : " ", 9);
357 summername[9] = '\0';
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000358 ins(d, "timezone", newintobject(winterzone));
359 ins(d, "altzone", newintobject(summerzone));
360 ins(d, "daylight", newintobject((long)(winterzone != summerzone)));
361 ins(d, "tzname", mkvalue("(zz)", wintername, summername));
Guido van Rossum234f9421993-06-17 12:35:49 +0000362 }
Guido van Rossumb6775db1994-08-01 11:34:53 +0000363#endif /* HAVE_TM_ZONE */
364#endif /* !HAVE_TZNAME */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000365}
366
367
Guido van Rossumb6775db1994-08-01 11:34:53 +0000368/* Implement floattime() for various platforms */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000369
Guido van Rossumb6775db1994-08-01 11:34:53 +0000370static double
371floattime()
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000372{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000373 /* There are three ways to get the time:
374 (1) gettimeofday() -- resolution in microseconds
375 (2) ftime() -- resolution in milliseconds
376 (3) time() -- resolution in seconds
377 In all cases the return value is a float in seconds.
378 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
379 fail, so we fall back on ftime() or time().
380 Note: clock resolution does not imply clock accuracy! */
381#ifdef HAVE_GETTIMEOFDAY
382 {
Guido van Rossum426035c1991-02-19 12:27:35 +0000383 struct timeval t;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000384#ifdef GETTIMEOFDAY_NO_TZ
385 if (gettimeofday(&t) == 0)
386 return (double)t.tv_sec + t.tv_usec*0.000001;
387#else /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000388 if (gettimeofday(&t, (struct timezone *)NULL) == 0)
389 return (double)t.tv_sec + t.tv_usec*0.000001;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000390#endif /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000391 }
392#endif /* !HAVE_GETTIMEOFDAY */
393 {
394#ifdef HAVE_FTIME
395 struct timeb t;
396 ftime(&t);
Guido van Rossum7b1e9741994-08-29 10:46:42 +0000397 return (double)t.time + (double)t.millitm * (double)0.001;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000398#else /* !HAVE_FTIME */
399 time_t secs;
400 time(&secs);
401 return (double)secs;
402#endif /* !HAVE_FTIME */
403 }
Guido van Rossum426035c1991-02-19 12:27:35 +0000404}
405
Guido van Rossumb6775db1994-08-01 11:34:53 +0000406
407/* Implement floatsleep() for various platforms.
408 When interrupted (or when another error occurs), return -1 and
409 set an exception; else return 0. */
410
411static int
Guido van Rossuma320fd31995-03-09 12:14:15 +0000412#ifdef MPW
413floatsleep(double secs)
414#else
Guido van Rossum775f4da1993-01-09 17:18:52 +0000415floatsleep(secs)
416 double secs;
Guido van Rossuma320fd31995-03-09 12:14:15 +0000417#endif /* MPW */
Guido van Rossum426035c1991-02-19 12:27:35 +0000418{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000419#ifdef HAVE_SELECT
Guido van Rossum426035c1991-02-19 12:27:35 +0000420 struct timeval t;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000421 double frac;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000422 frac = fmod(secs, 1.0);
423 secs = floor(secs);
424 t.tv_sec = (long)secs;
425 t.tv_usec = (long)(frac*1000000.0);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000426 if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
427 err_errno(IOError);
428 return -1;
429 }
430#else /* !HAVE_SELECT */
431#ifdef macintosh
432#define MacTicks (* (long *)0x16A)
433 long deadline;
434 deadline = MacTicks + (long)(secs * 60.0);
435 while (MacTicks < deadline) {
436 if (sigcheck())
437 return -1;
438 }
439#else /* !macintosh */
Guido van Rossumbceeac81996-05-23 22:53:47 +0000440#ifdef __WATCOMC__
441 /* XXX Can't interrupt this sleep */
442 delay((int)(secs * 1000 + 0.5)); /* delay() uses milliseconds */
443#else /* !__WATCOMC__ */
Guido van Rossume22e6441993-07-09 10:51:31 +0000444#ifdef MSDOS
Guido van Rossumb6775db1994-08-01 11:34:53 +0000445 struct timeb t1, t2;
446 double frac;
447 extern double fmod PROTO((double, double));
448 extern double floor PROTO((double));
449 if (secs <= 0.0)
450 return;
451 frac = fmod(secs, 1.0);
452 secs = floor(secs);
453 ftime(&t1);
454 t2.time = t1.time + (int)secs;
455 t2.millitm = t1.millitm + (int)(frac*1000.0);
456 while (t2.millitm >= 1000) {
457 t2.time++;
458 t2.millitm -= 1000;
459 }
460 for (;;) {
461#ifdef QUICKWIN
462 _wyield();
Guido van Rossum80c9d881991-04-16 08:47:51 +0000463#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000464 if (sigcheck())
465 return -1;
466 ftime(&t1);
467 if (t1.time > t2.time ||
468 t1.time == t2.time && t1.millitm >= t2.millitm)
469 break;
470 }
471#else /* !MSDOS */
472#ifdef _M_IX86
473 /* XXX Can't interrupt this sleep */
474 Sleep((int)(secs*1000));
475#else /* _M_IX86 */
476 /* XXX Can't interrupt this sleep */
477 sleep((int)secs);
478#endif /* _M_IX86 */
479#endif /* !MSDOS */
Guido van Rossumbceeac81996-05-23 22:53:47 +0000480#endif /* !__WATCOMC__ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000481#endif /* !macintosh */
482#endif /* !HAVE_SELECT */
483 return 0;
Guido van Rossum80c9d881991-04-16 08:47:51 +0000484}