blob: ae685084fc1d7f86c4bfc7439ca5a30bd318146d [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 Rossumcac6c721996-09-06 13:34:02 +000062#ifdef MS_WINDOWS
Guido van Rossumb6775db1994-08-01 11:34:53 +000063#include <windows.h>
64#define timezone _timezone
Guido van Rossumcac6c721996-09-06 13:34:02 +000065#ifndef tzname
Guido van Rossumcc081121995-03-14 15:05:41 +000066#define tzname _tzname
Guido van Rossumcac6c721996-09-06 13:34:02 +000067#endif
68#ifndef daylight
Guido van Rossumcc081121995-03-14 15:05:41 +000069#define daylight _daylight
Guido van Rossumcac6c721996-09-06 13:34:02 +000070#endif
Guido van Rossumcc081121995-03-14 15:05:41 +000071#define altzone _altzone
Guido van Rossumcac6c721996-09-06 13:34:02 +000072#endif /* MS_WINDOWS */
73#endif /* !__WATCOMC__ */
Guido van Rossum234f9421993-06-17 12:35:49 +000074
75/* Forward declarations */
Guido van Rossumb6775db1994-08-01 11:34:53 +000076static int floatsleep PROTO((double));
77static double floattime PROTO(());
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000078
79static object *
80time_time(self, args)
81 object *self;
82 object *args;
83{
Guido van Rossumb6775db1994-08-01 11:34:53 +000084 double secs;
Guido van Rossuma2b7f401993-01-04 09:09:59 +000085 if (!getnoarg(args))
86 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +000087 secs = floattime();
88 if (secs == 0.0) {
Guido van Rossuma2b7f401993-01-04 09:09:59 +000089 err_errno(IOError);
90 return NULL;
91 }
Guido van Rossumb6775db1994-08-01 11:34:53 +000092 return newfloatobject(secs);
93}
94
95#ifdef HAVE_CLOCK
96
97#ifndef CLOCKS_PER_SEC
Guido van Rossum1b66a4f1996-02-25 04:50:33 +000098#ifdef CLK_TCK
99#define CLOCKS_PER_SEC CLK_TCK
100#else
Guido van Rossumb6775db1994-08-01 11:34:53 +0000101#define CLOCKS_PER_SEC 1000000
102#endif
Guido van Rossum1b66a4f1996-02-25 04:50:33 +0000103#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000104
105static object *
106time_clock(self, args)
107 object *self;
108 object *args;
109{
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000110 if (!getnoarg(args))
111 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000112 return newfloatobject(((double)clock()) / CLOCKS_PER_SEC);
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000113}
Guido van Rossumb6775db1994-08-01 11:34:53 +0000114#endif /* HAVE_CLOCK */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000115
116static object *
117time_sleep(self, args)
118 object *self;
119 object *args;
120{
Guido van Rossum775f4da1993-01-09 17:18:52 +0000121 double secs;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000122 if (!getargs(args, "d", &secs))
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000123 return NULL;
Guido van Rossumff4949e1992-08-05 19:58:53 +0000124 BGN_SAVE
Guido van Rossumb6775db1994-08-01 11:34:53 +0000125 if (floatsleep(secs) != 0) {
Guido van Rossumff4949e1992-08-05 19:58:53 +0000126 RET_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000127 return NULL;
128 }
Guido van Rossumff4949e1992-08-05 19:58:53 +0000129 END_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000130 INCREF(None);
131 return None;
132}
133
Guido van Rossum234f9421993-06-17 12:35:49 +0000134static object *
135time_convert(when, function)
136 time_t when;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000137 struct tm * (*function) PROTO((const time_t *));
Guido van Rossum234f9421993-06-17 12:35:49 +0000138{
139 struct tm *p = function(&when);
140 return mkvalue("(iiiiiiiii)",
141 p->tm_year + 1900,
142 p->tm_mon + 1, /* Want January == 1 */
143 p->tm_mday,
144 p->tm_hour,
145 p->tm_min,
146 p->tm_sec,
147 (p->tm_wday + 6) % 7, /* Want Monday == 0 */
Guido van Rossum9e90a671993-06-24 11:10:19 +0000148 p->tm_yday + 1, /* Want January, 1 == 1 */
Guido van Rossum234f9421993-06-17 12:35:49 +0000149 p->tm_isdst);
150}
151
152static object *
153time_gmtime(self, args)
154 object *self;
155 object *args;
156{
157 double when;
158 if (!getargs(args, "d", &when))
159 return NULL;
160 return time_convert((time_t)when, gmtime);
161}
162
163static object *
164time_localtime(self, args)
165 object *self;
166 object *args;
167{
168 double when;
169 if (!getargs(args, "d", &when))
170 return NULL;
171 return time_convert((time_t)when, localtime);
172}
173
Guido van Rossum9e90a671993-06-24 11:10:19 +0000174static int
175gettmarg(args, p)
176 object *args;
177 struct tm *p;
178{
179 if (!getargs(args, "(iiiiiiiii)",
180 &p->tm_year,
181 &p->tm_mon,
182 &p->tm_mday,
183 &p->tm_hour,
184 &p->tm_min,
185 &p->tm_sec,
186 &p->tm_wday,
187 &p->tm_yday,
188 &p->tm_isdst))
189 return 0;
190 if (p->tm_year >= 1900)
191 p->tm_year -= 1900;
192 p->tm_mon--;
193 p->tm_wday = (p->tm_wday + 1) % 7;
194 p->tm_yday--;
195 return 1;
196}
197
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000198#ifdef HAVE_STRFTIME
199static object *
200time_strftime(self, args)
201 object *self;
202 object *args;
203{
204 struct tm buf;
205 const char *fmt;
206 char *outbuf = 0;
207 int i;
208
209 if (!PyArg_ParseTuple(args, "s(iiiiiiiii)",
210 &fmt,
211 &(buf.tm_year),
212 &(buf.tm_mon),
213 &(buf.tm_mday),
214 &(buf.tm_hour),
215 &(buf.tm_min),
216 &(buf.tm_sec),
217 &(buf.tm_wday),
218 &(buf.tm_yday),
219 &(buf.tm_isdst)))
220 return NULL;
221 if (buf.tm_year >= 1900)
222 buf.tm_year -= 1900;
223 buf.tm_mon--;
224 buf.tm_wday = (buf.tm_wday + 1) % 7;
225 buf.tm_yday--;
226 /* I hate these functions that presume you know how big the output */
227 /* will be ahead of time... */
228 for (i = 1024 ; i < 8192 ; i += 1024) {
229 outbuf = malloc(i);
230 if (outbuf == NULL) {
231 return err_nomem();
232 }
233 if (strftime(outbuf, i-1, fmt, &buf) != 0) {
234 object *ret;
235 ret = newstringobject(outbuf);
236 free(outbuf);
237 return ret;
238 }
239 free(outbuf);
240 }
241 return err_nomem();
242}
243#endif /* HAVE_STRFTIME */
244
Guido van Rossum9e90a671993-06-24 11:10:19 +0000245static object *
246time_asctime(self, args)
247 object *self;
248 object *args;
249{
250 struct tm buf;
251 char *p;
252 if (!gettmarg(args, &buf))
253 return NULL;
254 p = asctime(&buf);
255 if (p[24] == '\n')
256 p[24] = '\0';
257 return newstringobject(p);
258}
259
260static object *
261time_ctime(self, args)
262 object *self;
263 object *args;
264{
265 double dt;
266 time_t tt;
267 char *p;
268 if (!getargs(args, "d", &dt))
269 return NULL;
Guido van Rossumcac6c721996-09-06 13:34:02 +0000270 tt = (time_t)dt;
Guido van Rossum9e90a671993-06-24 11:10:19 +0000271 p = ctime(&tt);
272 if (p[24] == '\n')
273 p[24] = '\0';
274 return newstringobject(p);
275}
276
Guido van Rossum234f9421993-06-17 12:35:49 +0000277static object *
278time_mktime(self, args)
279 object *self;
280 object *args;
281{
282 struct tm buf;
Guido van Rossumbceeac81996-05-23 22:53:47 +0000283 time_t tt;
284 tt = time(&tt);
285 buf = *localtime(&tt);
Guido van Rossum9e90a671993-06-24 11:10:19 +0000286 if (!gettmarg(args, &buf))
Guido van Rossum234f9421993-06-17 12:35:49 +0000287 return NULL;
Guido van Rossumbceeac81996-05-23 22:53:47 +0000288 tt = mktime(&buf);
289 if (tt == (time_t)(-1)) {
290 err_setstr(OverflowError, "mktime argument out of range");
291 return NULL;
292 }
293 return newfloatobject((double)tt);
Guido van Rossum234f9421993-06-17 12:35:49 +0000294}
295
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000296static struct methodlist time_methods[] = {
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000297 {"time", time_time},
Guido van Rossumb6775db1994-08-01 11:34:53 +0000298#ifdef HAVE_CLOCK
299 {"clock", time_clock},
300#endif
301 {"sleep", time_sleep},
Guido van Rossum234f9421993-06-17 12:35:49 +0000302 {"gmtime", time_gmtime},
303 {"localtime", time_localtime},
Guido van Rossum9e90a671993-06-24 11:10:19 +0000304 {"asctime", time_asctime},
305 {"ctime", time_ctime},
Guido van Rossum234f9421993-06-17 12:35:49 +0000306 {"mktime", time_mktime},
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000307#ifdef HAVE_STRFTIME
Guido van Rossum5416e201996-02-13 00:14:09 +0000308 {"strftime", time_strftime, 1},
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000309#endif
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000310 {NULL, NULL} /* sentinel */
311};
312
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000313static void
314ins(d, name, v)
315 object *d;
316 char *name;
317 object *v;
318{
319 if (v == NULL)
320 fatal("Can't initialize time module -- NULL value");
321 if (dictinsert(d, name, v) != 0)
322 fatal("Can't initialize time module -- dictinsert failed");
323 DECREF(v);
324}
325
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000326void
327inittime()
328{
Jack Jansen8ccfc931995-10-03 14:39:44 +0000329 object *m, *d;
Guido van Rossum234f9421993-06-17 12:35:49 +0000330 m = initmodule("time", time_methods);
331 d = getmoduledict(m);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000332#ifdef HAVE_TZNAME
Guido van Rossum234f9421993-06-17 12:35:49 +0000333 tzset();
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000334 ins(d, "timezone", newintobject((long)timezone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000335#ifdef HAVE_ALTZONE
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000336 ins(d, "altzone", newintobject((long)altzone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000337#else
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000338 ins(d, "altzone", newintobject((long)timezone-3600));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000339#endif
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000340 ins(d, "daylight", newintobject((long)daylight));
341 ins(d, "tzname", mkvalue("(zz)", tzname[0], tzname[1]));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000342#else /* !HAVE_TZNAME */
343#if HAVE_TM_ZONE
Guido van Rossum234f9421993-06-17 12:35:49 +0000344 {
345#define YEAR ((time_t)((365 * 24 + 6) * 3600))
346 time_t t;
347 struct tm *p;
348 long winterzone, summerzone;
349 char wintername[10], summername[10];
Guido van Rossumb6775db1994-08-01 11:34:53 +0000350 /* XXX This won't work on the southern hemisphere.
351 XXX Anybody got a better idea? */
Guido van Rossum234f9421993-06-17 12:35:49 +0000352 t = (time((time_t *)0) / YEAR) * YEAR;
353 p = localtime(&t);
354 winterzone = -p->tm_gmtoff;
355 strncpy(wintername, p->tm_zone ? p->tm_zone : " ", 9);
356 wintername[9] = '\0';
357 t += YEAR/2;
358 p = localtime(&t);
359 summerzone = -p->tm_gmtoff;
360 strncpy(summername, p->tm_zone ? p->tm_zone : " ", 9);
361 summername[9] = '\0';
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000362 ins(d, "timezone", newintobject(winterzone));
363 ins(d, "altzone", newintobject(summerzone));
364 ins(d, "daylight", newintobject((long)(winterzone != summerzone)));
365 ins(d, "tzname", mkvalue("(zz)", wintername, summername));
Guido van Rossum234f9421993-06-17 12:35:49 +0000366 }
Guido van Rossumb6775db1994-08-01 11:34:53 +0000367#endif /* HAVE_TM_ZONE */
368#endif /* !HAVE_TZNAME */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000369}
370
371
Guido van Rossumb6775db1994-08-01 11:34:53 +0000372/* Implement floattime() for various platforms */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000373
Guido van Rossumb6775db1994-08-01 11:34:53 +0000374static double
375floattime()
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000376{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000377 /* There are three ways to get the time:
378 (1) gettimeofday() -- resolution in microseconds
379 (2) ftime() -- resolution in milliseconds
380 (3) time() -- resolution in seconds
381 In all cases the return value is a float in seconds.
382 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
383 fail, so we fall back on ftime() or time().
384 Note: clock resolution does not imply clock accuracy! */
385#ifdef HAVE_GETTIMEOFDAY
386 {
Guido van Rossum426035c1991-02-19 12:27:35 +0000387 struct timeval t;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000388#ifdef GETTIMEOFDAY_NO_TZ
389 if (gettimeofday(&t) == 0)
390 return (double)t.tv_sec + t.tv_usec*0.000001;
391#else /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000392 if (gettimeofday(&t, (struct timezone *)NULL) == 0)
393 return (double)t.tv_sec + t.tv_usec*0.000001;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000394#endif /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000395 }
396#endif /* !HAVE_GETTIMEOFDAY */
397 {
398#ifdef HAVE_FTIME
399 struct timeb t;
400 ftime(&t);
Guido van Rossum7b1e9741994-08-29 10:46:42 +0000401 return (double)t.time + (double)t.millitm * (double)0.001;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000402#else /* !HAVE_FTIME */
403 time_t secs;
404 time(&secs);
405 return (double)secs;
406#endif /* !HAVE_FTIME */
407 }
Guido van Rossum426035c1991-02-19 12:27:35 +0000408}
409
Guido van Rossumb6775db1994-08-01 11:34:53 +0000410
411/* Implement floatsleep() for various platforms.
412 When interrupted (or when another error occurs), return -1 and
413 set an exception; else return 0. */
414
415static int
Guido van Rossuma320fd31995-03-09 12:14:15 +0000416#ifdef MPW
417floatsleep(double secs)
418#else
Guido van Rossum775f4da1993-01-09 17:18:52 +0000419floatsleep(secs)
420 double secs;
Guido van Rossuma320fd31995-03-09 12:14:15 +0000421#endif /* MPW */
Guido van Rossum426035c1991-02-19 12:27:35 +0000422{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000423#ifdef HAVE_SELECT
Guido van Rossum426035c1991-02-19 12:27:35 +0000424 struct timeval t;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000425 double frac;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000426 frac = fmod(secs, 1.0);
427 secs = floor(secs);
428 t.tv_sec = (long)secs;
429 t.tv_usec = (long)(frac*1000000.0);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000430 if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
431 err_errno(IOError);
432 return -1;
433 }
434#else /* !HAVE_SELECT */
435#ifdef macintosh
436#define MacTicks (* (long *)0x16A)
437 long deadline;
438 deadline = MacTicks + (long)(secs * 60.0);
439 while (MacTicks < deadline) {
440 if (sigcheck())
441 return -1;
442 }
443#else /* !macintosh */
Guido van Rossumbceeac81996-05-23 22:53:47 +0000444#ifdef __WATCOMC__
445 /* XXX Can't interrupt this sleep */
446 delay((int)(secs * 1000 + 0.5)); /* delay() uses milliseconds */
447#else /* !__WATCOMC__ */
Guido van Rossume22e6441993-07-09 10:51:31 +0000448#ifdef MSDOS
Guido van Rossumb6775db1994-08-01 11:34:53 +0000449 struct timeb t1, t2;
450 double frac;
451 extern double fmod PROTO((double, double));
452 extern double floor PROTO((double));
453 if (secs <= 0.0)
454 return;
455 frac = fmod(secs, 1.0);
456 secs = floor(secs);
457 ftime(&t1);
458 t2.time = t1.time + (int)secs;
459 t2.millitm = t1.millitm + (int)(frac*1000.0);
460 while (t2.millitm >= 1000) {
461 t2.time++;
462 t2.millitm -= 1000;
463 }
464 for (;;) {
465#ifdef QUICKWIN
466 _wyield();
Guido van Rossum80c9d881991-04-16 08:47:51 +0000467#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000468 if (sigcheck())
469 return -1;
470 ftime(&t1);
471 if (t1.time > t2.time ||
472 t1.time == t2.time && t1.millitm >= t2.millitm)
473 break;
474 }
475#else /* !MSDOS */
Guido van Rossumcac6c721996-09-06 13:34:02 +0000476#ifdef MS_WINDOWS
Guido van Rossumb6775db1994-08-01 11:34:53 +0000477 /* XXX Can't interrupt this sleep */
478 Sleep((int)(secs*1000));
Guido van Rossumcac6c721996-09-06 13:34:02 +0000479#else /* !MS_WINDOWS */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000480 /* XXX Can't interrupt this sleep */
481 sleep((int)secs);
Guido van Rossumcac6c721996-09-06 13:34:02 +0000482#endif /* !MS_WINDOWS */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000483#endif /* !MSDOS */
Guido van Rossumbceeac81996-05-23 22:53:47 +0000484#endif /* !__WATCOMC__ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000485#endif /* !macintosh */
486#endif /* !HAVE_SELECT */
487 return 0;
Guido van Rossum80c9d881991-04-16 08:47:51 +0000488}