blob: ba2b700dfcf8113bc3a28c06fa19faf410d1c3d1 [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 Rossumb6775db1994-08-01 11:34:53 +000055#ifdef _M_IX86
56#include <windows.h>
57#define timezone _timezone
Guido van Rossumcc081121995-03-14 15:05:41 +000058#define tzname _tzname
59#define daylight _daylight
60#define altzone _altzone
Guido van Rossumb376a4a1993-11-23 17:53:17 +000061#endif
Guido van Rossum234f9421993-06-17 12:35:49 +000062
63/* Forward declarations */
Guido van Rossumb6775db1994-08-01 11:34:53 +000064static int floatsleep PROTO((double));
65static double floattime PROTO(());
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000066
67static object *
68time_time(self, args)
69 object *self;
70 object *args;
71{
Guido van Rossumb6775db1994-08-01 11:34:53 +000072 double secs;
Guido van Rossuma2b7f401993-01-04 09:09:59 +000073 if (!getnoarg(args))
74 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +000075 secs = floattime();
76 if (secs == 0.0) {
Guido van Rossuma2b7f401993-01-04 09:09:59 +000077 err_errno(IOError);
78 return NULL;
79 }
Guido van Rossumb6775db1994-08-01 11:34:53 +000080 return newfloatobject(secs);
81}
82
83#ifdef HAVE_CLOCK
84
85#ifndef CLOCKS_PER_SEC
86#define CLOCKS_PER_SEC 1000000
87#endif
88
89static object *
90time_clock(self, args)
91 object *self;
92 object *args;
93{
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000094 if (!getnoarg(args))
95 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +000096 return newfloatobject(((double)clock()) / CLOCKS_PER_SEC);
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000097}
Guido van Rossumb6775db1994-08-01 11:34:53 +000098#endif /* HAVE_CLOCK */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000099
100static object *
101time_sleep(self, args)
102 object *self;
103 object *args;
104{
Guido van Rossum775f4da1993-01-09 17:18:52 +0000105 double secs;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000106 if (!getargs(args, "d", &secs))
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000107 return NULL;
Guido van Rossumff4949e1992-08-05 19:58:53 +0000108 BGN_SAVE
Guido van Rossumb6775db1994-08-01 11:34:53 +0000109 if (floatsleep(secs) != 0) {
Guido van Rossumff4949e1992-08-05 19:58:53 +0000110 RET_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000111 return NULL;
112 }
Guido van Rossumff4949e1992-08-05 19:58:53 +0000113 END_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000114 INCREF(None);
115 return None;
116}
117
Guido van Rossum234f9421993-06-17 12:35:49 +0000118static object *
119time_convert(when, function)
120 time_t when;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000121 struct tm * (*function) PROTO((const time_t *));
Guido van Rossum234f9421993-06-17 12:35:49 +0000122{
123 struct tm *p = function(&when);
124 return mkvalue("(iiiiiiiii)",
125 p->tm_year + 1900,
126 p->tm_mon + 1, /* Want January == 1 */
127 p->tm_mday,
128 p->tm_hour,
129 p->tm_min,
130 p->tm_sec,
131 (p->tm_wday + 6) % 7, /* Want Monday == 0 */
Guido van Rossum9e90a671993-06-24 11:10:19 +0000132 p->tm_yday + 1, /* Want January, 1 == 1 */
Guido van Rossum234f9421993-06-17 12:35:49 +0000133 p->tm_isdst);
134}
135
136static object *
137time_gmtime(self, args)
138 object *self;
139 object *args;
140{
141 double when;
142 if (!getargs(args, "d", &when))
143 return NULL;
144 return time_convert((time_t)when, gmtime);
145}
146
147static object *
148time_localtime(self, args)
149 object *self;
150 object *args;
151{
152 double when;
153 if (!getargs(args, "d", &when))
154 return NULL;
155 return time_convert((time_t)when, localtime);
156}
157
Guido van Rossum9e90a671993-06-24 11:10:19 +0000158static int
159gettmarg(args, p)
160 object *args;
161 struct tm *p;
162{
163 if (!getargs(args, "(iiiiiiiii)",
164 &p->tm_year,
165 &p->tm_mon,
166 &p->tm_mday,
167 &p->tm_hour,
168 &p->tm_min,
169 &p->tm_sec,
170 &p->tm_wday,
171 &p->tm_yday,
172 &p->tm_isdst))
173 return 0;
174 if (p->tm_year >= 1900)
175 p->tm_year -= 1900;
176 p->tm_mon--;
177 p->tm_wday = (p->tm_wday + 1) % 7;
178 p->tm_yday--;
179 return 1;
180}
181
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000182#ifdef HAVE_STRFTIME
183static object *
184time_strftime(self, args)
185 object *self;
186 object *args;
187{
188 struct tm buf;
189 const char *fmt;
190 char *outbuf = 0;
191 int i;
192
193 if (!PyArg_ParseTuple(args, "s(iiiiiiiii)",
194 &fmt,
195 &(buf.tm_year),
196 &(buf.tm_mon),
197 &(buf.tm_mday),
198 &(buf.tm_hour),
199 &(buf.tm_min),
200 &(buf.tm_sec),
201 &(buf.tm_wday),
202 &(buf.tm_yday),
203 &(buf.tm_isdst)))
204 return NULL;
205 if (buf.tm_year >= 1900)
206 buf.tm_year -= 1900;
207 buf.tm_mon--;
208 buf.tm_wday = (buf.tm_wday + 1) % 7;
209 buf.tm_yday--;
210 /* I hate these functions that presume you know how big the output */
211 /* will be ahead of time... */
212 for (i = 1024 ; i < 8192 ; i += 1024) {
213 outbuf = malloc(i);
214 if (outbuf == NULL) {
215 return err_nomem();
216 }
217 if (strftime(outbuf, i-1, fmt, &buf) != 0) {
218 object *ret;
219 ret = newstringobject(outbuf);
220 free(outbuf);
221 return ret;
222 }
223 free(outbuf);
224 }
225 return err_nomem();
226}
227#endif /* HAVE_STRFTIME */
228
Guido van Rossum9e90a671993-06-24 11:10:19 +0000229static object *
230time_asctime(self, args)
231 object *self;
232 object *args;
233{
234 struct tm buf;
235 char *p;
236 if (!gettmarg(args, &buf))
237 return NULL;
238 p = asctime(&buf);
239 if (p[24] == '\n')
240 p[24] = '\0';
241 return newstringobject(p);
242}
243
244static object *
245time_ctime(self, args)
246 object *self;
247 object *args;
248{
249 double dt;
250 time_t tt;
251 char *p;
252 if (!getargs(args, "d", &dt))
253 return NULL;
254 tt = dt;
255 p = ctime(&tt);
256 if (p[24] == '\n')
257 p[24] = '\0';
258 return newstringobject(p);
259}
260
Guido van Rossum234f9421993-06-17 12:35:49 +0000261static object *
262time_mktime(self, args)
263 object *self;
264 object *args;
265{
266 struct tm buf;
Guido van Rossum9e90a671993-06-24 11:10:19 +0000267 if (!gettmarg(args, &buf))
Guido van Rossum234f9421993-06-17 12:35:49 +0000268 return NULL;
Guido van Rossum234f9421993-06-17 12:35:49 +0000269 return newintobject((long)mktime(&buf));
270}
271
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000272static struct methodlist time_methods[] = {
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000273 {"time", time_time},
Guido van Rossumb6775db1994-08-01 11:34:53 +0000274#ifdef HAVE_CLOCK
275 {"clock", time_clock},
276#endif
277 {"sleep", time_sleep},
Guido van Rossum234f9421993-06-17 12:35:49 +0000278 {"gmtime", time_gmtime},
279 {"localtime", time_localtime},
Guido van Rossum9e90a671993-06-24 11:10:19 +0000280 {"asctime", time_asctime},
281 {"ctime", time_ctime},
Guido van Rossum234f9421993-06-17 12:35:49 +0000282 {"mktime", time_mktime},
Guido van Rossum8d8c1ee1995-09-13 17:38:35 +0000283#ifdef HAVE_STRFTIME
284 {"strftime", time_strftime},
285#endif
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000286 {NULL, NULL} /* sentinel */
287};
288
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000289static void
290ins(d, name, v)
291 object *d;
292 char *name;
293 object *v;
294{
295 if (v == NULL)
296 fatal("Can't initialize time module -- NULL value");
297 if (dictinsert(d, name, v) != 0)
298 fatal("Can't initialize time module -- dictinsert failed");
299 DECREF(v);
300}
301
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000302void
303inittime()
304{
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000305 object *m, *d, *v;
Guido van Rossum234f9421993-06-17 12:35:49 +0000306 m = initmodule("time", time_methods);
307 d = getmoduledict(m);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000308#ifdef HAVE_TZNAME
Guido van Rossum234f9421993-06-17 12:35:49 +0000309 tzset();
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000310 ins(d, "timezone", newintobject((long)timezone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000311#ifdef HAVE_ALTZONE
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000312 ins(d, "altzone", newintobject((long)altzone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000313#else
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000314 ins(d, "altzone", newintobject((long)timezone-3600));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000315#endif
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000316 ins(d, "daylight", newintobject((long)daylight));
317 ins(d, "tzname", mkvalue("(zz)", tzname[0], tzname[1]));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000318#else /* !HAVE_TZNAME */
319#if HAVE_TM_ZONE
Guido van Rossum234f9421993-06-17 12:35:49 +0000320 {
321#define YEAR ((time_t)((365 * 24 + 6) * 3600))
322 time_t t;
323 struct tm *p;
324 long winterzone, summerzone;
325 char wintername[10], summername[10];
Guido van Rossumb6775db1994-08-01 11:34:53 +0000326 /* XXX This won't work on the southern hemisphere.
327 XXX Anybody got a better idea? */
Guido van Rossum234f9421993-06-17 12:35:49 +0000328 t = (time((time_t *)0) / YEAR) * YEAR;
329 p = localtime(&t);
330 winterzone = -p->tm_gmtoff;
331 strncpy(wintername, p->tm_zone ? p->tm_zone : " ", 9);
332 wintername[9] = '\0';
333 t += YEAR/2;
334 p = localtime(&t);
335 summerzone = -p->tm_gmtoff;
336 strncpy(summername, p->tm_zone ? p->tm_zone : " ", 9);
337 summername[9] = '\0';
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000338 ins(d, "timezone", newintobject(winterzone));
339 ins(d, "altzone", newintobject(summerzone));
340 ins(d, "daylight", newintobject((long)(winterzone != summerzone)));
341 ins(d, "tzname", mkvalue("(zz)", wintername, summername));
Guido van Rossum234f9421993-06-17 12:35:49 +0000342 }
Guido van Rossumb6775db1994-08-01 11:34:53 +0000343#endif /* HAVE_TM_ZONE */
344#endif /* !HAVE_TZNAME */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000345}
346
347
Guido van Rossumb6775db1994-08-01 11:34:53 +0000348/* Implement floattime() for various platforms */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000349
Guido van Rossumb6775db1994-08-01 11:34:53 +0000350static double
351floattime()
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000352{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000353 /* There are three ways to get the time:
354 (1) gettimeofday() -- resolution in microseconds
355 (2) ftime() -- resolution in milliseconds
356 (3) time() -- resolution in seconds
357 In all cases the return value is a float in seconds.
358 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
359 fail, so we fall back on ftime() or time().
360 Note: clock resolution does not imply clock accuracy! */
361#ifdef HAVE_GETTIMEOFDAY
362 {
Guido van Rossum426035c1991-02-19 12:27:35 +0000363 struct timeval t;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000364#ifdef GETTIMEOFDAY_NO_TZ
365 if (gettimeofday(&t) == 0)
366 return (double)t.tv_sec + t.tv_usec*0.000001;
367#else /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000368 if (gettimeofday(&t, (struct timezone *)NULL) == 0)
369 return (double)t.tv_sec + t.tv_usec*0.000001;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000370#endif /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000371 }
372#endif /* !HAVE_GETTIMEOFDAY */
373 {
374#ifdef HAVE_FTIME
375 struct timeb t;
376 ftime(&t);
Guido van Rossum7b1e9741994-08-29 10:46:42 +0000377 return (double)t.time + (double)t.millitm * (double)0.001;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000378#else /* !HAVE_FTIME */
379 time_t secs;
380 time(&secs);
381 return (double)secs;
382#endif /* !HAVE_FTIME */
383 }
Guido van Rossum426035c1991-02-19 12:27:35 +0000384}
385
Guido van Rossumb6775db1994-08-01 11:34:53 +0000386
387/* Implement floatsleep() for various platforms.
388 When interrupted (or when another error occurs), return -1 and
389 set an exception; else return 0. */
390
391static int
Guido van Rossuma320fd31995-03-09 12:14:15 +0000392#ifdef MPW
393floatsleep(double secs)
394#else
Guido van Rossum775f4da1993-01-09 17:18:52 +0000395floatsleep(secs)
396 double secs;
Guido van Rossuma320fd31995-03-09 12:14:15 +0000397#endif /* MPW */
Guido van Rossum426035c1991-02-19 12:27:35 +0000398{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000399#ifdef HAVE_SELECT
Guido van Rossum426035c1991-02-19 12:27:35 +0000400 struct timeval t;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000401 double frac;
402 extern double fmod PROTO((double, double));
403 extern double floor PROTO((double));
404 frac = fmod(secs, 1.0);
405 secs = floor(secs);
406 t.tv_sec = (long)secs;
407 t.tv_usec = (long)(frac*1000000.0);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000408 if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
409 err_errno(IOError);
410 return -1;
411 }
412#else /* !HAVE_SELECT */
413#ifdef macintosh
414#define MacTicks (* (long *)0x16A)
415 long deadline;
416 deadline = MacTicks + (long)(secs * 60.0);
417 while (MacTicks < deadline) {
418 if (sigcheck())
419 return -1;
420 }
421#else /* !macintosh */
Guido van Rossume22e6441993-07-09 10:51:31 +0000422#ifdef MSDOS
Guido van Rossumb6775db1994-08-01 11:34:53 +0000423 struct timeb t1, t2;
424 double frac;
425 extern double fmod PROTO((double, double));
426 extern double floor PROTO((double));
427 if (secs <= 0.0)
428 return;
429 frac = fmod(secs, 1.0);
430 secs = floor(secs);
431 ftime(&t1);
432 t2.time = t1.time + (int)secs;
433 t2.millitm = t1.millitm + (int)(frac*1000.0);
434 while (t2.millitm >= 1000) {
435 t2.time++;
436 t2.millitm -= 1000;
437 }
438 for (;;) {
439#ifdef QUICKWIN
440 _wyield();
Guido van Rossum80c9d881991-04-16 08:47:51 +0000441#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000442 if (sigcheck())
443 return -1;
444 ftime(&t1);
445 if (t1.time > t2.time ||
446 t1.time == t2.time && t1.millitm >= t2.millitm)
447 break;
448 }
449#else /* !MSDOS */
450#ifdef _M_IX86
451 /* XXX Can't interrupt this sleep */
452 Sleep((int)(secs*1000));
453#else /* _M_IX86 */
454 /* XXX Can't interrupt this sleep */
455 sleep((int)secs);
456#endif /* _M_IX86 */
457#endif /* !MSDOS */
458#endif /* !macintosh */
459#endif /* !HAVE_SELECT */
460 return 0;
Guido van Rossum80c9d881991-04-16 08:47:51 +0000461}