blob: d8c1b2b02799d1b1aefcd8915356c1c12e193c7d [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 Rossumbceeac81996-05-23 22:53:47 +000055#ifdef __WATCOMC__
56#include <i86.h>
57#else
Guido van Rossumb6775db1994-08-01 11:34:53 +000058#ifdef _M_IX86
59#include <windows.h>
60#define timezone _timezone
Guido van Rossumcc081121995-03-14 15:05:41 +000061#define tzname _tzname
62#define daylight _daylight
63#define altzone _altzone
Guido van Rossumb376a4a1993-11-23 17:53:17 +000064#endif
Guido van Rossumbceeac81996-05-23 22:53:47 +000065#endif
Guido van Rossum234f9421993-06-17 12:35:49 +000066
67/* Forward declarations */
Guido van Rossumb6775db1994-08-01 11:34:53 +000068static int floatsleep PROTO((double));
69static double floattime PROTO(());
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000070
71static object *
72time_time(self, args)
73 object *self;
74 object *args;
75{
Guido van Rossumb6775db1994-08-01 11:34:53 +000076 double secs;
Guido van Rossuma2b7f401993-01-04 09:09:59 +000077 if (!getnoarg(args))
78 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +000079 secs = floattime();
80 if (secs == 0.0) {
Guido van Rossuma2b7f401993-01-04 09:09:59 +000081 err_errno(IOError);
82 return NULL;
83 }
Guido van Rossumb6775db1994-08-01 11:34:53 +000084 return newfloatobject(secs);
85}
86
87#ifdef HAVE_CLOCK
88
89#ifndef CLOCKS_PER_SEC
Guido van Rossum1b66a4f1996-02-25 04:50:33 +000090#ifdef CLK_TCK
91#define CLOCKS_PER_SEC CLK_TCK
92#else
Guido van Rossumb6775db1994-08-01 11:34:53 +000093#define CLOCKS_PER_SEC 1000000
94#endif
Guido van Rossum1b66a4f1996-02-25 04:50:33 +000095#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +000096
97static object *
98time_clock(self, args)
99 object *self;
100 object *args;
101{
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000102 if (!getnoarg(args))
103 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000104 return newfloatobject(((double)clock()) / CLOCKS_PER_SEC);
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000105}
Guido van Rossumb6775db1994-08-01 11:34:53 +0000106#endif /* HAVE_CLOCK */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000107
108static object *
109time_sleep(self, args)
110 object *self;
111 object *args;
112{
Guido van Rossum775f4da1993-01-09 17:18:52 +0000113 double secs;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000114 if (!getargs(args, "d", &secs))
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000115 return NULL;
Guido van Rossumff4949e1992-08-05 19:58:53 +0000116 BGN_SAVE
Guido van Rossumb6775db1994-08-01 11:34:53 +0000117 if (floatsleep(secs) != 0) {
Guido van Rossumff4949e1992-08-05 19:58:53 +0000118 RET_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000119 return NULL;
120 }
Guido van Rossumff4949e1992-08-05 19:58:53 +0000121 END_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000122 INCREF(None);
123 return None;
124}
125
Guido van Rossum234f9421993-06-17 12:35:49 +0000126static object *
127time_convert(when, function)
128 time_t when;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000129 struct tm * (*function) PROTO((const time_t *));
Guido van Rossum234f9421993-06-17 12:35:49 +0000130{
131 struct tm *p = function(&when);
132 return mkvalue("(iiiiiiiii)",
133 p->tm_year + 1900,
134 p->tm_mon + 1, /* Want January == 1 */
135 p->tm_mday,
136 p->tm_hour,
137 p->tm_min,
138 p->tm_sec,
139 (p->tm_wday + 6) % 7, /* Want Monday == 0 */
Guido van Rossum9e90a671993-06-24 11:10:19 +0000140 p->tm_yday + 1, /* Want January, 1 == 1 */
Guido van Rossum234f9421993-06-17 12:35:49 +0000141 p->tm_isdst);
142}
143
144static object *
145time_gmtime(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, gmtime);
153}
154
155static object *
156time_localtime(self, args)
157 object *self;
158 object *args;
159{
160 double when;
161 if (!getargs(args, "d", &when))
162 return NULL;
163 return time_convert((time_t)when, localtime);
164}
165
Guido van Rossum9e90a671993-06-24 11:10:19 +0000166static int
167gettmarg(args, p)
168 object *args;
169 struct tm *p;
170{
171 if (!getargs(args, "(iiiiiiiii)",
172 &p->tm_year,
173 &p->tm_mon,
174 &p->tm_mday,
175 &p->tm_hour,
176 &p->tm_min,
177 &p->tm_sec,
178 &p->tm_wday,
179 &p->tm_yday,
180 &p->tm_isdst))
181 return 0;
182 if (p->tm_year >= 1900)
183 p->tm_year -= 1900;
184 p->tm_mon--;
185 p->tm_wday = (p->tm_wday + 1) % 7;
186 p->tm_yday--;
187 return 1;
188}
189
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000190#ifdef HAVE_STRFTIME
191static object *
192time_strftime(self, args)
193 object *self;
194 object *args;
195{
196 struct tm buf;
197 const char *fmt;
198 char *outbuf = 0;
199 int i;
200
201 if (!PyArg_ParseTuple(args, "s(iiiiiiiii)",
202 &fmt,
203 &(buf.tm_year),
204 &(buf.tm_mon),
205 &(buf.tm_mday),
206 &(buf.tm_hour),
207 &(buf.tm_min),
208 &(buf.tm_sec),
209 &(buf.tm_wday),
210 &(buf.tm_yday),
211 &(buf.tm_isdst)))
212 return NULL;
213 if (buf.tm_year >= 1900)
214 buf.tm_year -= 1900;
215 buf.tm_mon--;
216 buf.tm_wday = (buf.tm_wday + 1) % 7;
217 buf.tm_yday--;
218 /* I hate these functions that presume you know how big the output */
219 /* will be ahead of time... */
220 for (i = 1024 ; i < 8192 ; i += 1024) {
221 outbuf = malloc(i);
222 if (outbuf == NULL) {
223 return err_nomem();
224 }
225 if (strftime(outbuf, i-1, fmt, &buf) != 0) {
226 object *ret;
227 ret = newstringobject(outbuf);
228 free(outbuf);
229 return ret;
230 }
231 free(outbuf);
232 }
233 return err_nomem();
234}
235#endif /* HAVE_STRFTIME */
236
Guido van Rossum9e90a671993-06-24 11:10:19 +0000237static object *
238time_asctime(self, args)
239 object *self;
240 object *args;
241{
242 struct tm buf;
243 char *p;
244 if (!gettmarg(args, &buf))
245 return NULL;
246 p = asctime(&buf);
247 if (p[24] == '\n')
248 p[24] = '\0';
249 return newstringobject(p);
250}
251
252static object *
253time_ctime(self, args)
254 object *self;
255 object *args;
256{
257 double dt;
258 time_t tt;
259 char *p;
260 if (!getargs(args, "d", &dt))
261 return NULL;
262 tt = dt;
263 p = ctime(&tt);
264 if (p[24] == '\n')
265 p[24] = '\0';
266 return newstringobject(p);
267}
268
Guido van Rossum234f9421993-06-17 12:35:49 +0000269static object *
270time_mktime(self, args)
271 object *self;
272 object *args;
273{
274 struct tm buf;
Guido van Rossumbceeac81996-05-23 22:53:47 +0000275 time_t tt;
276 tt = time(&tt);
277 buf = *localtime(&tt);
Guido van Rossum9e90a671993-06-24 11:10:19 +0000278 if (!gettmarg(args, &buf))
Guido van Rossum234f9421993-06-17 12:35:49 +0000279 return NULL;
Guido van Rossumbceeac81996-05-23 22:53:47 +0000280 tt = mktime(&buf);
281 if (tt == (time_t)(-1)) {
282 err_setstr(OverflowError, "mktime argument out of range");
283 return NULL;
284 }
285 return newfloatobject((double)tt);
Guido van Rossum234f9421993-06-17 12:35:49 +0000286}
287
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000288static struct methodlist time_methods[] = {
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000289 {"time", time_time},
Guido van Rossumb6775db1994-08-01 11:34:53 +0000290#ifdef HAVE_CLOCK
291 {"clock", time_clock},
292#endif
293 {"sleep", time_sleep},
Guido van Rossum234f9421993-06-17 12:35:49 +0000294 {"gmtime", time_gmtime},
295 {"localtime", time_localtime},
Guido van Rossum9e90a671993-06-24 11:10:19 +0000296 {"asctime", time_asctime},
297 {"ctime", time_ctime},
Guido van Rossum234f9421993-06-17 12:35:49 +0000298 {"mktime", time_mktime},
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000299#ifdef HAVE_STRFTIME
Guido van Rossum5416e201996-02-13 00:14:09 +0000300 {"strftime", time_strftime, 1},
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000301#endif
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000302 {NULL, NULL} /* sentinel */
303};
304
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000305static void
306ins(d, name, v)
307 object *d;
308 char *name;
309 object *v;
310{
311 if (v == NULL)
312 fatal("Can't initialize time module -- NULL value");
313 if (dictinsert(d, name, v) != 0)
314 fatal("Can't initialize time module -- dictinsert failed");
315 DECREF(v);
316}
317
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000318void
319inittime()
320{
Jack Jansen8ccfc931995-10-03 14:39:44 +0000321 object *m, *d;
Guido van Rossum234f9421993-06-17 12:35:49 +0000322 m = initmodule("time", time_methods);
323 d = getmoduledict(m);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000324#ifdef HAVE_TZNAME
Guido van Rossum234f9421993-06-17 12:35:49 +0000325 tzset();
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000326 ins(d, "timezone", newintobject((long)timezone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000327#ifdef HAVE_ALTZONE
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000328 ins(d, "altzone", newintobject((long)altzone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000329#else
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000330 ins(d, "altzone", newintobject((long)timezone-3600));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000331#endif
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000332 ins(d, "daylight", newintobject((long)daylight));
333 ins(d, "tzname", mkvalue("(zz)", tzname[0], tzname[1]));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000334#else /* !HAVE_TZNAME */
335#if HAVE_TM_ZONE
Guido van Rossum234f9421993-06-17 12:35:49 +0000336 {
337#define YEAR ((time_t)((365 * 24 + 6) * 3600))
338 time_t t;
339 struct tm *p;
340 long winterzone, summerzone;
341 char wintername[10], summername[10];
Guido van Rossumb6775db1994-08-01 11:34:53 +0000342 /* XXX This won't work on the southern hemisphere.
343 XXX Anybody got a better idea? */
Guido van Rossum234f9421993-06-17 12:35:49 +0000344 t = (time((time_t *)0) / YEAR) * YEAR;
345 p = localtime(&t);
346 winterzone = -p->tm_gmtoff;
347 strncpy(wintername, p->tm_zone ? p->tm_zone : " ", 9);
348 wintername[9] = '\0';
349 t += YEAR/2;
350 p = localtime(&t);
351 summerzone = -p->tm_gmtoff;
352 strncpy(summername, p->tm_zone ? p->tm_zone : " ", 9);
353 summername[9] = '\0';
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000354 ins(d, "timezone", newintobject(winterzone));
355 ins(d, "altzone", newintobject(summerzone));
356 ins(d, "daylight", newintobject((long)(winterzone != summerzone)));
357 ins(d, "tzname", mkvalue("(zz)", wintername, summername));
Guido van Rossum234f9421993-06-17 12:35:49 +0000358 }
Guido van Rossumb6775db1994-08-01 11:34:53 +0000359#endif /* HAVE_TM_ZONE */
360#endif /* !HAVE_TZNAME */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000361}
362
363
Guido van Rossumb6775db1994-08-01 11:34:53 +0000364/* Implement floattime() for various platforms */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000365
Guido van Rossumb6775db1994-08-01 11:34:53 +0000366static double
367floattime()
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000368{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000369 /* There are three ways to get the time:
370 (1) gettimeofday() -- resolution in microseconds
371 (2) ftime() -- resolution in milliseconds
372 (3) time() -- resolution in seconds
373 In all cases the return value is a float in seconds.
374 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
375 fail, so we fall back on ftime() or time().
376 Note: clock resolution does not imply clock accuracy! */
377#ifdef HAVE_GETTIMEOFDAY
378 {
Guido van Rossum426035c1991-02-19 12:27:35 +0000379 struct timeval t;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000380#ifdef GETTIMEOFDAY_NO_TZ
381 if (gettimeofday(&t) == 0)
382 return (double)t.tv_sec + t.tv_usec*0.000001;
383#else /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000384 if (gettimeofday(&t, (struct timezone *)NULL) == 0)
385 return (double)t.tv_sec + t.tv_usec*0.000001;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000386#endif /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000387 }
388#endif /* !HAVE_GETTIMEOFDAY */
389 {
390#ifdef HAVE_FTIME
391 struct timeb t;
392 ftime(&t);
Guido van Rossum7b1e9741994-08-29 10:46:42 +0000393 return (double)t.time + (double)t.millitm * (double)0.001;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000394#else /* !HAVE_FTIME */
395 time_t secs;
396 time(&secs);
397 return (double)secs;
398#endif /* !HAVE_FTIME */
399 }
Guido van Rossum426035c1991-02-19 12:27:35 +0000400}
401
Guido van Rossumb6775db1994-08-01 11:34:53 +0000402
403/* Implement floatsleep() for various platforms.
404 When interrupted (or when another error occurs), return -1 and
405 set an exception; else return 0. */
406
407static int
Guido van Rossuma320fd31995-03-09 12:14:15 +0000408#ifdef MPW
409floatsleep(double secs)
410#else
Guido van Rossum775f4da1993-01-09 17:18:52 +0000411floatsleep(secs)
412 double secs;
Guido van Rossuma320fd31995-03-09 12:14:15 +0000413#endif /* MPW */
Guido van Rossum426035c1991-02-19 12:27:35 +0000414{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000415#ifdef HAVE_SELECT
Guido van Rossum426035c1991-02-19 12:27:35 +0000416 struct timeval t;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000417 double frac;
418 extern double fmod PROTO((double, double));
419 extern double floor PROTO((double));
420 frac = fmod(secs, 1.0);
421 secs = floor(secs);
422 t.tv_sec = (long)secs;
423 t.tv_usec = (long)(frac*1000000.0);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000424 if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
425 err_errno(IOError);
426 return -1;
427 }
428#else /* !HAVE_SELECT */
429#ifdef macintosh
430#define MacTicks (* (long *)0x16A)
431 long deadline;
432 deadline = MacTicks + (long)(secs * 60.0);
433 while (MacTicks < deadline) {
434 if (sigcheck())
435 return -1;
436 }
437#else /* !macintosh */
Guido van Rossumbceeac81996-05-23 22:53:47 +0000438#ifdef __WATCOMC__
439 /* XXX Can't interrupt this sleep */
440 delay((int)(secs * 1000 + 0.5)); /* delay() uses milliseconds */
441#else /* !__WATCOMC__ */
Guido van Rossume22e6441993-07-09 10:51:31 +0000442#ifdef MSDOS
Guido van Rossumb6775db1994-08-01 11:34:53 +0000443 struct timeb t1, t2;
444 double frac;
445 extern double fmod PROTO((double, double));
446 extern double floor PROTO((double));
447 if (secs <= 0.0)
448 return;
449 frac = fmod(secs, 1.0);
450 secs = floor(secs);
451 ftime(&t1);
452 t2.time = t1.time + (int)secs;
453 t2.millitm = t1.millitm + (int)(frac*1000.0);
454 while (t2.millitm >= 1000) {
455 t2.time++;
456 t2.millitm -= 1000;
457 }
458 for (;;) {
459#ifdef QUICKWIN
460 _wyield();
Guido van Rossum80c9d881991-04-16 08:47:51 +0000461#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000462 if (sigcheck())
463 return -1;
464 ftime(&t1);
465 if (t1.time > t2.time ||
466 t1.time == t2.time && t1.millitm >= t2.millitm)
467 break;
468 }
469#else /* !MSDOS */
470#ifdef _M_IX86
471 /* XXX Can't interrupt this sleep */
472 Sleep((int)(secs*1000));
473#else /* _M_IX86 */
474 /* XXX Can't interrupt this sleep */
475 sleep((int)secs);
476#endif /* _M_IX86 */
477#endif /* !MSDOS */
Guido van Rossumbceeac81996-05-23 22:53:47 +0000478#endif /* !__WATCOMC__ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000479#endif /* !macintosh */
480#endif /* !HAVE_SELECT */
481 return 0;
Guido van Rossum80c9d881991-04-16 08:47:51 +0000482}