blob: aee599ae71a5239e7e70ed2882555f7b13dfdc41 [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>
Guido van Rossumb2fb3641996-09-07 00:47:35 +000064#ifdef MS_WIN16
65/* These overrides not needed for Win32 */
Guido van Rossumb6775db1994-08-01 11:34:53 +000066#define timezone _timezone
Guido van Rossumcc081121995-03-14 15:05:41 +000067#define tzname _tzname
68#define daylight _daylight
69#define altzone _altzone
Guido van Rossumb2fb3641996-09-07 00:47:35 +000070#endif /* MS_WIN16 */
Guido van Rossumcac6c721996-09-06 13:34:02 +000071#endif /* MS_WINDOWS */
72#endif /* !__WATCOMC__ */
Guido van Rossum234f9421993-06-17 12:35:49 +000073
74/* Forward declarations */
Guido van Rossumb6775db1994-08-01 11:34:53 +000075static int floatsleep PROTO((double));
76static double floattime PROTO(());
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000077
78static object *
79time_time(self, args)
80 object *self;
81 object *args;
82{
Guido van Rossumb6775db1994-08-01 11:34:53 +000083 double secs;
Guido van Rossuma2b7f401993-01-04 09:09:59 +000084 if (!getnoarg(args))
85 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +000086 secs = floattime();
87 if (secs == 0.0) {
Guido van Rossuma2b7f401993-01-04 09:09:59 +000088 err_errno(IOError);
89 return NULL;
90 }
Guido van Rossumb6775db1994-08-01 11:34:53 +000091 return newfloatobject(secs);
92}
93
94#ifdef HAVE_CLOCK
95
96#ifndef CLOCKS_PER_SEC
Guido van Rossum1b66a4f1996-02-25 04:50:33 +000097#ifdef CLK_TCK
98#define CLOCKS_PER_SEC CLK_TCK
99#else
Guido van Rossumb6775db1994-08-01 11:34:53 +0000100#define CLOCKS_PER_SEC 1000000
101#endif
Guido van Rossum1b66a4f1996-02-25 04:50:33 +0000102#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000103
104static object *
105time_clock(self, args)
106 object *self;
107 object *args;
108{
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000109 if (!getnoarg(args))
110 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000111 return newfloatobject(((double)clock()) / CLOCKS_PER_SEC);
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000112}
Guido van Rossumb6775db1994-08-01 11:34:53 +0000113#endif /* HAVE_CLOCK */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000114
115static object *
116time_sleep(self, args)
117 object *self;
118 object *args;
119{
Guido van Rossum775f4da1993-01-09 17:18:52 +0000120 double secs;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000121 if (!getargs(args, "d", &secs))
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000122 return NULL;
Guido van Rossumff4949e1992-08-05 19:58:53 +0000123 BGN_SAVE
Guido van Rossumb6775db1994-08-01 11:34:53 +0000124 if (floatsleep(secs) != 0) {
Guido van Rossumff4949e1992-08-05 19:58:53 +0000125 RET_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000126 return NULL;
127 }
Guido van Rossumff4949e1992-08-05 19:58:53 +0000128 END_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000129 INCREF(None);
130 return None;
131}
132
Guido van Rossum234f9421993-06-17 12:35:49 +0000133static object *
134time_convert(when, function)
135 time_t when;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000136 struct tm * (*function) PROTO((const time_t *));
Guido van Rossum234f9421993-06-17 12:35:49 +0000137{
138 struct tm *p = function(&when);
139 return mkvalue("(iiiiiiiii)",
140 p->tm_year + 1900,
141 p->tm_mon + 1, /* Want January == 1 */
142 p->tm_mday,
143 p->tm_hour,
144 p->tm_min,
145 p->tm_sec,
146 (p->tm_wday + 6) % 7, /* Want Monday == 0 */
Guido van Rossum9e90a671993-06-24 11:10:19 +0000147 p->tm_yday + 1, /* Want January, 1 == 1 */
Guido van Rossum234f9421993-06-17 12:35:49 +0000148 p->tm_isdst);
149}
150
151static object *
152time_gmtime(self, args)
153 object *self;
154 object *args;
155{
156 double when;
157 if (!getargs(args, "d", &when))
158 return NULL;
159 return time_convert((time_t)when, gmtime);
160}
161
162static object *
163time_localtime(self, args)
164 object *self;
165 object *args;
166{
167 double when;
168 if (!getargs(args, "d", &when))
169 return NULL;
170 return time_convert((time_t)when, localtime);
171}
172
Guido van Rossum9e90a671993-06-24 11:10:19 +0000173static int
174gettmarg(args, p)
175 object *args;
176 struct tm *p;
177{
178 if (!getargs(args, "(iiiiiiiii)",
179 &p->tm_year,
180 &p->tm_mon,
181 &p->tm_mday,
182 &p->tm_hour,
183 &p->tm_min,
184 &p->tm_sec,
185 &p->tm_wday,
186 &p->tm_yday,
187 &p->tm_isdst))
188 return 0;
189 if (p->tm_year >= 1900)
190 p->tm_year -= 1900;
191 p->tm_mon--;
192 p->tm_wday = (p->tm_wday + 1) % 7;
193 p->tm_yday--;
194 return 1;
195}
196
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000197#ifdef HAVE_STRFTIME
198static object *
199time_strftime(self, args)
200 object *self;
201 object *args;
202{
203 struct tm buf;
204 const char *fmt;
205 char *outbuf = 0;
206 int i;
207
208 if (!PyArg_ParseTuple(args, "s(iiiiiiiii)",
209 &fmt,
210 &(buf.tm_year),
211 &(buf.tm_mon),
212 &(buf.tm_mday),
213 &(buf.tm_hour),
214 &(buf.tm_min),
215 &(buf.tm_sec),
216 &(buf.tm_wday),
217 &(buf.tm_yday),
218 &(buf.tm_isdst)))
219 return NULL;
220 if (buf.tm_year >= 1900)
221 buf.tm_year -= 1900;
222 buf.tm_mon--;
223 buf.tm_wday = (buf.tm_wday + 1) % 7;
224 buf.tm_yday--;
225 /* I hate these functions that presume you know how big the output */
226 /* will be ahead of time... */
227 for (i = 1024 ; i < 8192 ; i += 1024) {
228 outbuf = malloc(i);
229 if (outbuf == NULL) {
230 return err_nomem();
231 }
232 if (strftime(outbuf, i-1, fmt, &buf) != 0) {
233 object *ret;
234 ret = newstringobject(outbuf);
235 free(outbuf);
236 return ret;
237 }
238 free(outbuf);
239 }
240 return err_nomem();
241}
242#endif /* HAVE_STRFTIME */
243
Guido van Rossum9e90a671993-06-24 11:10:19 +0000244static object *
245time_asctime(self, args)
246 object *self;
247 object *args;
248{
249 struct tm buf;
250 char *p;
251 if (!gettmarg(args, &buf))
252 return NULL;
253 p = asctime(&buf);
254 if (p[24] == '\n')
255 p[24] = '\0';
256 return newstringobject(p);
257}
258
259static object *
260time_ctime(self, args)
261 object *self;
262 object *args;
263{
264 double dt;
265 time_t tt;
266 char *p;
267 if (!getargs(args, "d", &dt))
268 return NULL;
Guido van Rossumcac6c721996-09-06 13:34:02 +0000269 tt = (time_t)dt;
Guido van Rossum9e90a671993-06-24 11:10:19 +0000270 p = ctime(&tt);
271 if (p[24] == '\n')
272 p[24] = '\0';
273 return newstringobject(p);
274}
275
Guido van Rossum234f9421993-06-17 12:35:49 +0000276static object *
277time_mktime(self, args)
278 object *self;
279 object *args;
280{
281 struct tm buf;
Guido van Rossumbceeac81996-05-23 22:53:47 +0000282 time_t tt;
283 tt = time(&tt);
284 buf = *localtime(&tt);
Guido van Rossum9e90a671993-06-24 11:10:19 +0000285 if (!gettmarg(args, &buf))
Guido van Rossum234f9421993-06-17 12:35:49 +0000286 return NULL;
Guido van Rossumbceeac81996-05-23 22:53:47 +0000287 tt = mktime(&buf);
288 if (tt == (time_t)(-1)) {
289 err_setstr(OverflowError, "mktime argument out of range");
290 return NULL;
291 }
292 return newfloatobject((double)tt);
Guido van Rossum234f9421993-06-17 12:35:49 +0000293}
294
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000295static struct methodlist time_methods[] = {
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000296 {"time", time_time},
Guido van Rossumb6775db1994-08-01 11:34:53 +0000297#ifdef HAVE_CLOCK
298 {"clock", time_clock},
299#endif
300 {"sleep", time_sleep},
Guido van Rossum234f9421993-06-17 12:35:49 +0000301 {"gmtime", time_gmtime},
302 {"localtime", time_localtime},
Guido van Rossum9e90a671993-06-24 11:10:19 +0000303 {"asctime", time_asctime},
304 {"ctime", time_ctime},
Guido van Rossum234f9421993-06-17 12:35:49 +0000305 {"mktime", time_mktime},
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000306#ifdef HAVE_STRFTIME
Guido van Rossum5416e201996-02-13 00:14:09 +0000307 {"strftime", time_strftime, 1},
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000308#endif
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000309 {NULL, NULL} /* sentinel */
310};
311
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000312static void
313ins(d, name, v)
314 object *d;
315 char *name;
316 object *v;
317{
318 if (v == NULL)
319 fatal("Can't initialize time module -- NULL value");
320 if (dictinsert(d, name, v) != 0)
321 fatal("Can't initialize time module -- dictinsert failed");
322 DECREF(v);
323}
324
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000325void
326inittime()
327{
Jack Jansen8ccfc931995-10-03 14:39:44 +0000328 object *m, *d;
Guido van Rossum234f9421993-06-17 12:35:49 +0000329 m = initmodule("time", time_methods);
330 d = getmoduledict(m);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000331#ifdef HAVE_TZNAME
Guido van Rossum234f9421993-06-17 12:35:49 +0000332 tzset();
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000333 ins(d, "timezone", newintobject((long)timezone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000334#ifdef HAVE_ALTZONE
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000335 ins(d, "altzone", newintobject((long)altzone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000336#else
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000337 ins(d, "altzone", newintobject((long)timezone-3600));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000338#endif
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000339 ins(d, "daylight", newintobject((long)daylight));
340 ins(d, "tzname", mkvalue("(zz)", tzname[0], tzname[1]));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000341#else /* !HAVE_TZNAME */
342#if HAVE_TM_ZONE
Guido van Rossum234f9421993-06-17 12:35:49 +0000343 {
344#define YEAR ((time_t)((365 * 24 + 6) * 3600))
345 time_t t;
346 struct tm *p;
347 long winterzone, summerzone;
348 char wintername[10], summername[10];
Guido van Rossumb6775db1994-08-01 11:34:53 +0000349 /* XXX This won't work on the southern hemisphere.
350 XXX Anybody got a better idea? */
Guido van Rossum234f9421993-06-17 12:35:49 +0000351 t = (time((time_t *)0) / YEAR) * YEAR;
352 p = localtime(&t);
353 winterzone = -p->tm_gmtoff;
354 strncpy(wintername, p->tm_zone ? p->tm_zone : " ", 9);
355 wintername[9] = '\0';
356 t += YEAR/2;
357 p = localtime(&t);
358 summerzone = -p->tm_gmtoff;
359 strncpy(summername, p->tm_zone ? p->tm_zone : " ", 9);
360 summername[9] = '\0';
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000361 ins(d, "timezone", newintobject(winterzone));
362 ins(d, "altzone", newintobject(summerzone));
363 ins(d, "daylight", newintobject((long)(winterzone != summerzone)));
364 ins(d, "tzname", mkvalue("(zz)", wintername, summername));
Guido van Rossum234f9421993-06-17 12:35:49 +0000365 }
Guido van Rossumb6775db1994-08-01 11:34:53 +0000366#endif /* HAVE_TM_ZONE */
367#endif /* !HAVE_TZNAME */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000368}
369
370
Guido van Rossumb6775db1994-08-01 11:34:53 +0000371/* Implement floattime() for various platforms */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000372
Guido van Rossumb6775db1994-08-01 11:34:53 +0000373static double
374floattime()
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000375{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000376 /* There are three ways to get the time:
377 (1) gettimeofday() -- resolution in microseconds
378 (2) ftime() -- resolution in milliseconds
379 (3) time() -- resolution in seconds
380 In all cases the return value is a float in seconds.
381 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
382 fail, so we fall back on ftime() or time().
383 Note: clock resolution does not imply clock accuracy! */
384#ifdef HAVE_GETTIMEOFDAY
385 {
Guido van Rossum426035c1991-02-19 12:27:35 +0000386 struct timeval t;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000387#ifdef GETTIMEOFDAY_NO_TZ
388 if (gettimeofday(&t) == 0)
389 return (double)t.tv_sec + t.tv_usec*0.000001;
390#else /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000391 if (gettimeofday(&t, (struct timezone *)NULL) == 0)
392 return (double)t.tv_sec + t.tv_usec*0.000001;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000393#endif /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000394 }
395#endif /* !HAVE_GETTIMEOFDAY */
396 {
397#ifdef HAVE_FTIME
398 struct timeb t;
399 ftime(&t);
Guido van Rossum7b1e9741994-08-29 10:46:42 +0000400 return (double)t.time + (double)t.millitm * (double)0.001;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000401#else /* !HAVE_FTIME */
402 time_t secs;
403 time(&secs);
404 return (double)secs;
405#endif /* !HAVE_FTIME */
406 }
Guido van Rossum426035c1991-02-19 12:27:35 +0000407}
408
Guido van Rossumb6775db1994-08-01 11:34:53 +0000409
410/* Implement floatsleep() for various platforms.
411 When interrupted (or when another error occurs), return -1 and
412 set an exception; else return 0. */
413
414static int
Guido van Rossuma320fd31995-03-09 12:14:15 +0000415#ifdef MPW
416floatsleep(double secs)
417#else
Guido van Rossum775f4da1993-01-09 17:18:52 +0000418floatsleep(secs)
419 double secs;
Guido van Rossuma320fd31995-03-09 12:14:15 +0000420#endif /* MPW */
Guido van Rossum426035c1991-02-19 12:27:35 +0000421{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000422#ifdef HAVE_SELECT
Guido van Rossum426035c1991-02-19 12:27:35 +0000423 struct timeval t;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000424 double frac;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000425 frac = fmod(secs, 1.0);
426 secs = floor(secs);
427 t.tv_sec = (long)secs;
428 t.tv_usec = (long)(frac*1000000.0);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000429 if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
430 err_errno(IOError);
431 return -1;
432 }
433#else /* !HAVE_SELECT */
434#ifdef macintosh
435#define MacTicks (* (long *)0x16A)
436 long deadline;
437 deadline = MacTicks + (long)(secs * 60.0);
438 while (MacTicks < deadline) {
439 if (sigcheck())
440 return -1;
441 }
442#else /* !macintosh */
Guido van Rossumbceeac81996-05-23 22:53:47 +0000443#ifdef __WATCOMC__
444 /* XXX Can't interrupt this sleep */
445 delay((int)(secs * 1000 + 0.5)); /* delay() uses milliseconds */
446#else /* !__WATCOMC__ */
Guido van Rossume22e6441993-07-09 10:51:31 +0000447#ifdef MSDOS
Guido van Rossumb6775db1994-08-01 11:34:53 +0000448 struct timeb t1, t2;
449 double frac;
450 extern double fmod PROTO((double, double));
451 extern double floor PROTO((double));
452 if (secs <= 0.0)
453 return;
454 frac = fmod(secs, 1.0);
455 secs = floor(secs);
456 ftime(&t1);
457 t2.time = t1.time + (int)secs;
458 t2.millitm = t1.millitm + (int)(frac*1000.0);
459 while (t2.millitm >= 1000) {
460 t2.time++;
461 t2.millitm -= 1000;
462 }
463 for (;;) {
464#ifdef QUICKWIN
465 _wyield();
Guido van Rossum80c9d881991-04-16 08:47:51 +0000466#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000467 if (sigcheck())
468 return -1;
469 ftime(&t1);
470 if (t1.time > t2.time ||
471 t1.time == t2.time && t1.millitm >= t2.millitm)
472 break;
473 }
474#else /* !MSDOS */
Guido van Rossumb2fb3641996-09-07 00:47:35 +0000475#ifdef MS_WIN32
Guido van Rossumb6775db1994-08-01 11:34:53 +0000476 /* XXX Can't interrupt this sleep */
477 Sleep((int)(secs*1000));
Guido van Rossumb2fb3641996-09-07 00:47:35 +0000478#else /* !MS_WIN32 */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000479 /* XXX Can't interrupt this sleep */
480 sleep((int)secs);
Guido van Rossumb2fb3641996-09-07 00:47:35 +0000481#endif /* !MS_WIN32 */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000482#endif /* !MSDOS */
Guido van Rossumbceeac81996-05-23 22:53:47 +0000483#endif /* !__WATCOMC__ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000484#endif /* !macintosh */
485#endif /* !HAVE_SELECT */
486 return 0;
Guido van Rossum80c9d881991-04-16 08:47:51 +0000487}