blob: 6e6abfb2191dbe0835539e879532966cbfabcb25 [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{
Guido van Rossum6e8583d1996-10-08 14:19:52 +0000138 struct tm *p;
139 errno = 0;
140 p = function(&when);
141 if (p == NULL) {
142#ifdef EINVAL
143 if (errno == NULL)
144 errno = EINVAL;
145#endif
146 return err_errno(IOError);
147 }
Guido van Rossum234f9421993-06-17 12:35:49 +0000148 return mkvalue("(iiiiiiiii)",
149 p->tm_year + 1900,
150 p->tm_mon + 1, /* Want January == 1 */
151 p->tm_mday,
152 p->tm_hour,
153 p->tm_min,
154 p->tm_sec,
155 (p->tm_wday + 6) % 7, /* Want Monday == 0 */
Guido van Rossum9e90a671993-06-24 11:10:19 +0000156 p->tm_yday + 1, /* Want January, 1 == 1 */
Guido van Rossum234f9421993-06-17 12:35:49 +0000157 p->tm_isdst);
158}
159
160static object *
161time_gmtime(self, args)
162 object *self;
163 object *args;
164{
165 double when;
166 if (!getargs(args, "d", &when))
167 return NULL;
168 return time_convert((time_t)when, gmtime);
169}
170
171static object *
172time_localtime(self, args)
173 object *self;
174 object *args;
175{
176 double when;
177 if (!getargs(args, "d", &when))
178 return NULL;
179 return time_convert((time_t)when, localtime);
180}
181
Guido van Rossum9e90a671993-06-24 11:10:19 +0000182static int
183gettmarg(args, p)
184 object *args;
185 struct tm *p;
186{
187 if (!getargs(args, "(iiiiiiiii)",
188 &p->tm_year,
189 &p->tm_mon,
190 &p->tm_mday,
191 &p->tm_hour,
192 &p->tm_min,
193 &p->tm_sec,
194 &p->tm_wday,
195 &p->tm_yday,
196 &p->tm_isdst))
197 return 0;
198 if (p->tm_year >= 1900)
199 p->tm_year -= 1900;
200 p->tm_mon--;
201 p->tm_wday = (p->tm_wday + 1) % 7;
202 p->tm_yday--;
203 return 1;
204}
205
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000206#ifdef HAVE_STRFTIME
207static object *
208time_strftime(self, args)
209 object *self;
210 object *args;
211{
212 struct tm buf;
213 const char *fmt;
214 char *outbuf = 0;
215 int i;
216
217 if (!PyArg_ParseTuple(args, "s(iiiiiiiii)",
218 &fmt,
219 &(buf.tm_year),
220 &(buf.tm_mon),
221 &(buf.tm_mday),
222 &(buf.tm_hour),
223 &(buf.tm_min),
224 &(buf.tm_sec),
225 &(buf.tm_wday),
226 &(buf.tm_yday),
227 &(buf.tm_isdst)))
228 return NULL;
229 if (buf.tm_year >= 1900)
230 buf.tm_year -= 1900;
231 buf.tm_mon--;
232 buf.tm_wday = (buf.tm_wday + 1) % 7;
233 buf.tm_yday--;
234 /* I hate these functions that presume you know how big the output */
235 /* will be ahead of time... */
236 for (i = 1024 ; i < 8192 ; i += 1024) {
237 outbuf = malloc(i);
238 if (outbuf == NULL) {
239 return err_nomem();
240 }
241 if (strftime(outbuf, i-1, fmt, &buf) != 0) {
242 object *ret;
243 ret = newstringobject(outbuf);
244 free(outbuf);
245 return ret;
246 }
247 free(outbuf);
248 }
249 return err_nomem();
250}
251#endif /* HAVE_STRFTIME */
252
Guido van Rossum9e90a671993-06-24 11:10:19 +0000253static object *
254time_asctime(self, args)
255 object *self;
256 object *args;
257{
258 struct tm buf;
259 char *p;
260 if (!gettmarg(args, &buf))
261 return NULL;
262 p = asctime(&buf);
263 if (p[24] == '\n')
264 p[24] = '\0';
265 return newstringobject(p);
266}
267
268static object *
269time_ctime(self, args)
270 object *self;
271 object *args;
272{
273 double dt;
274 time_t tt;
275 char *p;
276 if (!getargs(args, "d", &dt))
277 return NULL;
Guido van Rossumcac6c721996-09-06 13:34:02 +0000278 tt = (time_t)dt;
Guido van Rossum9e90a671993-06-24 11:10:19 +0000279 p = ctime(&tt);
280 if (p[24] == '\n')
281 p[24] = '\0';
282 return newstringobject(p);
283}
284
Guido van Rossum234f9421993-06-17 12:35:49 +0000285static object *
286time_mktime(self, args)
287 object *self;
288 object *args;
289{
290 struct tm buf;
Guido van Rossumbceeac81996-05-23 22:53:47 +0000291 time_t tt;
292 tt = time(&tt);
293 buf = *localtime(&tt);
Guido van Rossum9e90a671993-06-24 11:10:19 +0000294 if (!gettmarg(args, &buf))
Guido van Rossum234f9421993-06-17 12:35:49 +0000295 return NULL;
Guido van Rossumbceeac81996-05-23 22:53:47 +0000296 tt = mktime(&buf);
297 if (tt == (time_t)(-1)) {
298 err_setstr(OverflowError, "mktime argument out of range");
299 return NULL;
300 }
301 return newfloatobject((double)tt);
Guido van Rossum234f9421993-06-17 12:35:49 +0000302}
303
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000304static struct methodlist time_methods[] = {
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000305 {"time", time_time},
Guido van Rossumb6775db1994-08-01 11:34:53 +0000306#ifdef HAVE_CLOCK
307 {"clock", time_clock},
308#endif
309 {"sleep", time_sleep},
Guido van Rossum234f9421993-06-17 12:35:49 +0000310 {"gmtime", time_gmtime},
311 {"localtime", time_localtime},
Guido van Rossum9e90a671993-06-24 11:10:19 +0000312 {"asctime", time_asctime},
313 {"ctime", time_ctime},
Guido van Rossum234f9421993-06-17 12:35:49 +0000314 {"mktime", time_mktime},
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000315#ifdef HAVE_STRFTIME
Guido van Rossum5416e201996-02-13 00:14:09 +0000316 {"strftime", time_strftime, 1},
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000317#endif
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000318 {NULL, NULL} /* sentinel */
319};
320
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000321static void
322ins(d, name, v)
323 object *d;
324 char *name;
325 object *v;
326{
327 if (v == NULL)
328 fatal("Can't initialize time module -- NULL value");
329 if (dictinsert(d, name, v) != 0)
330 fatal("Can't initialize time module -- dictinsert failed");
331 DECREF(v);
332}
333
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000334void
335inittime()
336{
Jack Jansen8ccfc931995-10-03 14:39:44 +0000337 object *m, *d;
Guido van Rossum234f9421993-06-17 12:35:49 +0000338 m = initmodule("time", time_methods);
339 d = getmoduledict(m);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000340#ifdef HAVE_TZNAME
Guido van Rossum234f9421993-06-17 12:35:49 +0000341 tzset();
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000342 ins(d, "timezone", newintobject((long)timezone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000343#ifdef HAVE_ALTZONE
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000344 ins(d, "altzone", newintobject((long)altzone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000345#else
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000346 ins(d, "altzone", newintobject((long)timezone-3600));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000347#endif
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000348 ins(d, "daylight", newintobject((long)daylight));
349 ins(d, "tzname", mkvalue("(zz)", tzname[0], tzname[1]));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000350#else /* !HAVE_TZNAME */
351#if HAVE_TM_ZONE
Guido van Rossum234f9421993-06-17 12:35:49 +0000352 {
353#define YEAR ((time_t)((365 * 24 + 6) * 3600))
354 time_t t;
355 struct tm *p;
356 long winterzone, summerzone;
357 char wintername[10], summername[10];
Guido van Rossumb6775db1994-08-01 11:34:53 +0000358 /* XXX This won't work on the southern hemisphere.
359 XXX Anybody got a better idea? */
Guido van Rossum234f9421993-06-17 12:35:49 +0000360 t = (time((time_t *)0) / YEAR) * YEAR;
361 p = localtime(&t);
362 winterzone = -p->tm_gmtoff;
363 strncpy(wintername, p->tm_zone ? p->tm_zone : " ", 9);
364 wintername[9] = '\0';
365 t += YEAR/2;
366 p = localtime(&t);
367 summerzone = -p->tm_gmtoff;
368 strncpy(summername, p->tm_zone ? p->tm_zone : " ", 9);
369 summername[9] = '\0';
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000370 ins(d, "timezone", newintobject(winterzone));
371 ins(d, "altzone", newintobject(summerzone));
372 ins(d, "daylight", newintobject((long)(winterzone != summerzone)));
373 ins(d, "tzname", mkvalue("(zz)", wintername, summername));
Guido van Rossum234f9421993-06-17 12:35:49 +0000374 }
Guido van Rossumb6775db1994-08-01 11:34:53 +0000375#endif /* HAVE_TM_ZONE */
376#endif /* !HAVE_TZNAME */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000377}
378
379
Guido van Rossumb6775db1994-08-01 11:34:53 +0000380/* Implement floattime() for various platforms */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000381
Guido van Rossumb6775db1994-08-01 11:34:53 +0000382static double
383floattime()
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000384{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000385 /* There are three ways to get the time:
386 (1) gettimeofday() -- resolution in microseconds
387 (2) ftime() -- resolution in milliseconds
388 (3) time() -- resolution in seconds
389 In all cases the return value is a float in seconds.
390 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
391 fail, so we fall back on ftime() or time().
392 Note: clock resolution does not imply clock accuracy! */
393#ifdef HAVE_GETTIMEOFDAY
394 {
Guido van Rossum426035c1991-02-19 12:27:35 +0000395 struct timeval t;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000396#ifdef GETTIMEOFDAY_NO_TZ
397 if (gettimeofday(&t) == 0)
398 return (double)t.tv_sec + t.tv_usec*0.000001;
399#else /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000400 if (gettimeofday(&t, (struct timezone *)NULL) == 0)
401 return (double)t.tv_sec + t.tv_usec*0.000001;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000402#endif /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000403 }
404#endif /* !HAVE_GETTIMEOFDAY */
405 {
406#ifdef HAVE_FTIME
407 struct timeb t;
408 ftime(&t);
Guido van Rossum7b1e9741994-08-29 10:46:42 +0000409 return (double)t.time + (double)t.millitm * (double)0.001;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000410#else /* !HAVE_FTIME */
411 time_t secs;
412 time(&secs);
413 return (double)secs;
414#endif /* !HAVE_FTIME */
415 }
Guido van Rossum426035c1991-02-19 12:27:35 +0000416}
417
Guido van Rossumb6775db1994-08-01 11:34:53 +0000418
419/* Implement floatsleep() for various platforms.
420 When interrupted (or when another error occurs), return -1 and
421 set an exception; else return 0. */
422
423static int
Guido van Rossuma320fd31995-03-09 12:14:15 +0000424#ifdef MPW
425floatsleep(double secs)
426#else
Guido van Rossum775f4da1993-01-09 17:18:52 +0000427floatsleep(secs)
428 double secs;
Guido van Rossuma320fd31995-03-09 12:14:15 +0000429#endif /* MPW */
Guido van Rossum426035c1991-02-19 12:27:35 +0000430{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000431#ifdef HAVE_SELECT
Guido van Rossum426035c1991-02-19 12:27:35 +0000432 struct timeval t;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000433 double frac;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000434 frac = fmod(secs, 1.0);
435 secs = floor(secs);
436 t.tv_sec = (long)secs;
437 t.tv_usec = (long)(frac*1000000.0);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000438 if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
439 err_errno(IOError);
440 return -1;
441 }
442#else /* !HAVE_SELECT */
443#ifdef macintosh
444#define MacTicks (* (long *)0x16A)
445 long deadline;
446 deadline = MacTicks + (long)(secs * 60.0);
447 while (MacTicks < deadline) {
448 if (sigcheck())
449 return -1;
450 }
451#else /* !macintosh */
Guido van Rossumbceeac81996-05-23 22:53:47 +0000452#ifdef __WATCOMC__
453 /* XXX Can't interrupt this sleep */
454 delay((int)(secs * 1000 + 0.5)); /* delay() uses milliseconds */
455#else /* !__WATCOMC__ */
Guido van Rossume22e6441993-07-09 10:51:31 +0000456#ifdef MSDOS
Guido van Rossumb6775db1994-08-01 11:34:53 +0000457 struct timeb t1, t2;
458 double frac;
459 extern double fmod PROTO((double, double));
460 extern double floor PROTO((double));
461 if (secs <= 0.0)
462 return;
463 frac = fmod(secs, 1.0);
464 secs = floor(secs);
465 ftime(&t1);
466 t2.time = t1.time + (int)secs;
467 t2.millitm = t1.millitm + (int)(frac*1000.0);
468 while (t2.millitm >= 1000) {
469 t2.time++;
470 t2.millitm -= 1000;
471 }
472 for (;;) {
473#ifdef QUICKWIN
474 _wyield();
Guido van Rossum80c9d881991-04-16 08:47:51 +0000475#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000476 if (sigcheck())
477 return -1;
478 ftime(&t1);
479 if (t1.time > t2.time ||
480 t1.time == t2.time && t1.millitm >= t2.millitm)
481 break;
482 }
483#else /* !MSDOS */
Guido van Rossumb2fb3641996-09-07 00:47:35 +0000484#ifdef MS_WIN32
Guido van Rossumb6775db1994-08-01 11:34:53 +0000485 /* XXX Can't interrupt this sleep */
486 Sleep((int)(secs*1000));
Guido van Rossumb2fb3641996-09-07 00:47:35 +0000487#else /* !MS_WIN32 */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000488 /* XXX Can't interrupt this sleep */
489 sleep((int)secs);
Guido van Rossumb2fb3641996-09-07 00:47:35 +0000490#endif /* !MS_WIN32 */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000491#endif /* !MSDOS */
Guido van Rossumbceeac81996-05-23 22:53:47 +0000492#endif /* !__WATCOMC__ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000493#endif /* !macintosh */
494#endif /* !HAVE_SELECT */
495 return 0;
Guido van Rossum80c9d881991-04-16 08:47:51 +0000496}