blob: f7738354cd51bb5ed9068f0688a8a27f88bfcb00 [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
182static object *
183time_asctime(self, args)
184 object *self;
185 object *args;
186{
187 struct tm buf;
188 char *p;
189 if (!gettmarg(args, &buf))
190 return NULL;
191 p = asctime(&buf);
192 if (p[24] == '\n')
193 p[24] = '\0';
194 return newstringobject(p);
195}
196
197static object *
198time_ctime(self, args)
199 object *self;
200 object *args;
201{
202 double dt;
203 time_t tt;
204 char *p;
205 if (!getargs(args, "d", &dt))
206 return NULL;
207 tt = dt;
208 p = ctime(&tt);
209 if (p[24] == '\n')
210 p[24] = '\0';
211 return newstringobject(p);
212}
213
Guido van Rossum234f9421993-06-17 12:35:49 +0000214static object *
215time_mktime(self, args)
216 object *self;
217 object *args;
218{
219 struct tm buf;
Guido van Rossum9e90a671993-06-24 11:10:19 +0000220 if (!gettmarg(args, &buf))
Guido van Rossum234f9421993-06-17 12:35:49 +0000221 return NULL;
Guido van Rossum234f9421993-06-17 12:35:49 +0000222 return newintobject((long)mktime(&buf));
223}
224
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000225static struct methodlist time_methods[] = {
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000226 {"time", time_time},
Guido van Rossumb6775db1994-08-01 11:34:53 +0000227#ifdef HAVE_CLOCK
228 {"clock", time_clock},
229#endif
230 {"sleep", time_sleep},
Guido van Rossum234f9421993-06-17 12:35:49 +0000231 {"gmtime", time_gmtime},
232 {"localtime", time_localtime},
Guido van Rossum9e90a671993-06-24 11:10:19 +0000233 {"asctime", time_asctime},
234 {"ctime", time_ctime},
Guido van Rossum234f9421993-06-17 12:35:49 +0000235 {"mktime", time_mktime},
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000236 {NULL, NULL} /* sentinel */
237};
238
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000239static void
240ins(d, name, v)
241 object *d;
242 char *name;
243 object *v;
244{
245 if (v == NULL)
246 fatal("Can't initialize time module -- NULL value");
247 if (dictinsert(d, name, v) != 0)
248 fatal("Can't initialize time module -- dictinsert failed");
249 DECREF(v);
250}
251
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000252void
253inittime()
254{
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000255 object *m, *d, *v;
Guido van Rossum234f9421993-06-17 12:35:49 +0000256 m = initmodule("time", time_methods);
257 d = getmoduledict(m);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000258#ifdef HAVE_TZNAME
Guido van Rossum234f9421993-06-17 12:35:49 +0000259 tzset();
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000260 ins(d, "timezone", newintobject((long)timezone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000261#ifdef HAVE_ALTZONE
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000262 ins(d, "altzone", newintobject((long)altzone));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000263#else
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000264 ins(d, "altzone", newintobject((long)timezone-3600));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000265#endif
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000266 ins(d, "daylight", newintobject((long)daylight));
267 ins(d, "tzname", mkvalue("(zz)", tzname[0], tzname[1]));
Guido van Rossumb6775db1994-08-01 11:34:53 +0000268#else /* !HAVE_TZNAME */
269#if HAVE_TM_ZONE
Guido van Rossum234f9421993-06-17 12:35:49 +0000270 {
271#define YEAR ((time_t)((365 * 24 + 6) * 3600))
272 time_t t;
273 struct tm *p;
274 long winterzone, summerzone;
275 char wintername[10], summername[10];
Guido van Rossumb6775db1994-08-01 11:34:53 +0000276 /* XXX This won't work on the southern hemisphere.
277 XXX Anybody got a better idea? */
Guido van Rossum234f9421993-06-17 12:35:49 +0000278 t = (time((time_t *)0) / YEAR) * YEAR;
279 p = localtime(&t);
280 winterzone = -p->tm_gmtoff;
281 strncpy(wintername, p->tm_zone ? p->tm_zone : " ", 9);
282 wintername[9] = '\0';
283 t += YEAR/2;
284 p = localtime(&t);
285 summerzone = -p->tm_gmtoff;
286 strncpy(summername, p->tm_zone ? p->tm_zone : " ", 9);
287 summername[9] = '\0';
Guido van Rossum8239f0f1995-01-22 00:49:01 +0000288 ins(d, "timezone", newintobject(winterzone));
289 ins(d, "altzone", newintobject(summerzone));
290 ins(d, "daylight", newintobject((long)(winterzone != summerzone)));
291 ins(d, "tzname", mkvalue("(zz)", wintername, summername));
Guido van Rossum234f9421993-06-17 12:35:49 +0000292 }
Guido van Rossumb6775db1994-08-01 11:34:53 +0000293#endif /* HAVE_TM_ZONE */
294#endif /* !HAVE_TZNAME */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000295}
296
297
Guido van Rossumb6775db1994-08-01 11:34:53 +0000298/* Implement floattime() for various platforms */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000299
Guido van Rossumb6775db1994-08-01 11:34:53 +0000300static double
301floattime()
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000302{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000303 /* There are three ways to get the time:
304 (1) gettimeofday() -- resolution in microseconds
305 (2) ftime() -- resolution in milliseconds
306 (3) time() -- resolution in seconds
307 In all cases the return value is a float in seconds.
308 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
309 fail, so we fall back on ftime() or time().
310 Note: clock resolution does not imply clock accuracy! */
311#ifdef HAVE_GETTIMEOFDAY
312 {
Guido van Rossum426035c1991-02-19 12:27:35 +0000313 struct timeval t;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000314#ifdef GETTIMEOFDAY_NO_TZ
315 if (gettimeofday(&t) == 0)
316 return (double)t.tv_sec + t.tv_usec*0.000001;
317#else /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000318 if (gettimeofday(&t, (struct timezone *)NULL) == 0)
319 return (double)t.tv_sec + t.tv_usec*0.000001;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000320#endif /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000321 }
322#endif /* !HAVE_GETTIMEOFDAY */
323 {
324#ifdef HAVE_FTIME
325 struct timeb t;
326 ftime(&t);
Guido van Rossum7b1e9741994-08-29 10:46:42 +0000327 return (double)t.time + (double)t.millitm * (double)0.001;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000328#else /* !HAVE_FTIME */
329 time_t secs;
330 time(&secs);
331 return (double)secs;
332#endif /* !HAVE_FTIME */
333 }
Guido van Rossum426035c1991-02-19 12:27:35 +0000334}
335
Guido van Rossumb6775db1994-08-01 11:34:53 +0000336
337/* Implement floatsleep() for various platforms.
338 When interrupted (or when another error occurs), return -1 and
339 set an exception; else return 0. */
340
341static int
Guido van Rossuma320fd31995-03-09 12:14:15 +0000342#ifdef MPW
343floatsleep(double secs)
344#else
Guido van Rossum775f4da1993-01-09 17:18:52 +0000345floatsleep(secs)
346 double secs;
Guido van Rossuma320fd31995-03-09 12:14:15 +0000347#endif /* MPW */
Guido van Rossum426035c1991-02-19 12:27:35 +0000348{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000349#ifdef HAVE_SELECT
Guido van Rossum426035c1991-02-19 12:27:35 +0000350 struct timeval t;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000351 double frac;
352 extern double fmod PROTO((double, double));
353 extern double floor PROTO((double));
354 frac = fmod(secs, 1.0);
355 secs = floor(secs);
356 t.tv_sec = (long)secs;
357 t.tv_usec = (long)(frac*1000000.0);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000358 if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
359 err_errno(IOError);
360 return -1;
361 }
362#else /* !HAVE_SELECT */
363#ifdef macintosh
364#define MacTicks (* (long *)0x16A)
365 long deadline;
366 deadline = MacTicks + (long)(secs * 60.0);
367 while (MacTicks < deadline) {
368 if (sigcheck())
369 return -1;
370 }
371#else /* !macintosh */
Guido van Rossume22e6441993-07-09 10:51:31 +0000372#ifdef MSDOS
Guido van Rossumb6775db1994-08-01 11:34:53 +0000373 struct timeb t1, t2;
374 double frac;
375 extern double fmod PROTO((double, double));
376 extern double floor PROTO((double));
377 if (secs <= 0.0)
378 return;
379 frac = fmod(secs, 1.0);
380 secs = floor(secs);
381 ftime(&t1);
382 t2.time = t1.time + (int)secs;
383 t2.millitm = t1.millitm + (int)(frac*1000.0);
384 while (t2.millitm >= 1000) {
385 t2.time++;
386 t2.millitm -= 1000;
387 }
388 for (;;) {
389#ifdef QUICKWIN
390 _wyield();
Guido van Rossum80c9d881991-04-16 08:47:51 +0000391#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000392 if (sigcheck())
393 return -1;
394 ftime(&t1);
395 if (t1.time > t2.time ||
396 t1.time == t2.time && t1.millitm >= t2.millitm)
397 break;
398 }
399#else /* !MSDOS */
400#ifdef _M_IX86
401 /* XXX Can't interrupt this sleep */
402 Sleep((int)(secs*1000));
403#else /* _M_IX86 */
404 /* XXX Can't interrupt this sleep */
405 sleep((int)secs);
406#endif /* _M_IX86 */
407#endif /* !MSDOS */
408#endif /* !macintosh */
409#endif /* !HAVE_SELECT */
410 return 0;
Guido van Rossum80c9d881991-04-16 08:47:51 +0000411}