blob: d35eba8d33768f2676eda78c7543a5acc25c602f [file] [log] [blame]
Guido van Rossumf70e43a1991-02-19 12:39:46 +00001/***********************************************************
Guido van Rossumb6775db1994-08-01 11:34:53 +00002Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
Guido van Rossum775f4da1993-01-09 17:18:52 +00003Amsterdam, The 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 Rossumb376a4a1993-11-23 17:53:17 +000058#endif
Guido van Rossum234f9421993-06-17 12:35:49 +000059
60/* Forward declarations */
Guido van Rossumb6775db1994-08-01 11:34:53 +000061static int floatsleep PROTO((double));
62static double floattime PROTO(());
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000063
64static object *
65time_time(self, args)
66 object *self;
67 object *args;
68{
Guido van Rossumb6775db1994-08-01 11:34:53 +000069 double secs;
Guido van Rossuma2b7f401993-01-04 09:09:59 +000070 if (!getnoarg(args))
71 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +000072 secs = floattime();
73 if (secs == 0.0) {
Guido van Rossuma2b7f401993-01-04 09:09:59 +000074 err_errno(IOError);
75 return NULL;
76 }
Guido van Rossumb6775db1994-08-01 11:34:53 +000077 return newfloatobject(secs);
78}
79
80#ifdef HAVE_CLOCK
81
82#ifndef CLOCKS_PER_SEC
83#define CLOCKS_PER_SEC 1000000
84#endif
85
86static object *
87time_clock(self, args)
88 object *self;
89 object *args;
90{
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000091 if (!getnoarg(args))
92 return NULL;
Guido van Rossumb6775db1994-08-01 11:34:53 +000093 return newfloatobject(((double)clock()) / CLOCKS_PER_SEC);
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000094}
Guido van Rossumb6775db1994-08-01 11:34:53 +000095#endif /* HAVE_CLOCK */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +000096
97static object *
98time_sleep(self, args)
99 object *self;
100 object *args;
101{
Guido van Rossum775f4da1993-01-09 17:18:52 +0000102 double secs;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000103 if (!getargs(args, "d", &secs))
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000104 return NULL;
Guido van Rossumff4949e1992-08-05 19:58:53 +0000105 BGN_SAVE
Guido van Rossumb6775db1994-08-01 11:34:53 +0000106 if (floatsleep(secs) != 0) {
Guido van Rossumff4949e1992-08-05 19:58:53 +0000107 RET_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000108 return NULL;
109 }
Guido van Rossumff4949e1992-08-05 19:58:53 +0000110 END_SAVE
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000111 INCREF(None);
112 return None;
113}
114
Guido van Rossum234f9421993-06-17 12:35:49 +0000115static object *
116time_convert(when, function)
117 time_t when;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000118 struct tm * (*function) PROTO((const time_t *));
Guido van Rossum234f9421993-06-17 12:35:49 +0000119{
120 struct tm *p = function(&when);
121 return mkvalue("(iiiiiiiii)",
122 p->tm_year + 1900,
123 p->tm_mon + 1, /* Want January == 1 */
124 p->tm_mday,
125 p->tm_hour,
126 p->tm_min,
127 p->tm_sec,
128 (p->tm_wday + 6) % 7, /* Want Monday == 0 */
Guido van Rossum9e90a671993-06-24 11:10:19 +0000129 p->tm_yday + 1, /* Want January, 1 == 1 */
Guido van Rossum234f9421993-06-17 12:35:49 +0000130 p->tm_isdst);
131}
132
133static object *
134time_gmtime(self, args)
135 object *self;
136 object *args;
137{
138 double when;
139 if (!getargs(args, "d", &when))
140 return NULL;
141 return time_convert((time_t)when, gmtime);
142}
143
144static object *
145time_localtime(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, localtime);
153}
154
Guido van Rossum9e90a671993-06-24 11:10:19 +0000155static int
156gettmarg(args, p)
157 object *args;
158 struct tm *p;
159{
160 if (!getargs(args, "(iiiiiiiii)",
161 &p->tm_year,
162 &p->tm_mon,
163 &p->tm_mday,
164 &p->tm_hour,
165 &p->tm_min,
166 &p->tm_sec,
167 &p->tm_wday,
168 &p->tm_yday,
169 &p->tm_isdst))
170 return 0;
171 if (p->tm_year >= 1900)
172 p->tm_year -= 1900;
173 p->tm_mon--;
174 p->tm_wday = (p->tm_wday + 1) % 7;
175 p->tm_yday--;
176 return 1;
177}
178
179static object *
180time_asctime(self, args)
181 object *self;
182 object *args;
183{
184 struct tm buf;
185 char *p;
186 if (!gettmarg(args, &buf))
187 return NULL;
188 p = asctime(&buf);
189 if (p[24] == '\n')
190 p[24] = '\0';
191 return newstringobject(p);
192}
193
194static object *
195time_ctime(self, args)
196 object *self;
197 object *args;
198{
199 double dt;
200 time_t tt;
201 char *p;
202 if (!getargs(args, "d", &dt))
203 return NULL;
204 tt = dt;
205 p = ctime(&tt);
206 if (p[24] == '\n')
207 p[24] = '\0';
208 return newstringobject(p);
209}
210
Guido van Rossum234f9421993-06-17 12:35:49 +0000211static object *
212time_mktime(self, args)
213 object *self;
214 object *args;
215{
216 struct tm buf;
Guido van Rossum9e90a671993-06-24 11:10:19 +0000217 if (!gettmarg(args, &buf))
Guido van Rossum234f9421993-06-17 12:35:49 +0000218 return NULL;
Guido van Rossum234f9421993-06-17 12:35:49 +0000219 return newintobject((long)mktime(&buf));
220}
221
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000222static struct methodlist time_methods[] = {
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000223 {"time", time_time},
Guido van Rossumb6775db1994-08-01 11:34:53 +0000224#ifdef HAVE_CLOCK
225 {"clock", time_clock},
226#endif
227 {"sleep", time_sleep},
Guido van Rossum234f9421993-06-17 12:35:49 +0000228 {"gmtime", time_gmtime},
229 {"localtime", time_localtime},
Guido van Rossum9e90a671993-06-24 11:10:19 +0000230 {"asctime", time_asctime},
231 {"ctime", time_ctime},
Guido van Rossum234f9421993-06-17 12:35:49 +0000232 {"mktime", time_mktime},
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000233 {NULL, NULL} /* sentinel */
234};
235
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000236void
237inittime()
238{
Guido van Rossum234f9421993-06-17 12:35:49 +0000239 object *m, *d;
240 m = initmodule("time", time_methods);
241 d = getmoduledict(m);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000242#ifdef HAVE_TZNAME
Guido van Rossum234f9421993-06-17 12:35:49 +0000243 tzset();
Guido van Rossumb6775db1994-08-01 11:34:53 +0000244 dictinsert(d, "timezone", newintobject((long)timezone));
245#ifdef HAVE_ALTZONE
246 dictinsert(d, "altzone", newintobject((long)altzone));
247#else
248 dictinsert(d, "altzone", newintobject((long)timezone-3600));
249#endif
250 dictinsert(d, "daylight", newintobject((long)daylight));
251 dictinsert(d, "tzname", mkvalue("(zz)", tzname[0], tzname[1]));
252#else /* !HAVE_TZNAME */
253#if HAVE_TM_ZONE
Guido van Rossum234f9421993-06-17 12:35:49 +0000254 {
255#define YEAR ((time_t)((365 * 24 + 6) * 3600))
256 time_t t;
257 struct tm *p;
258 long winterzone, summerzone;
259 char wintername[10], summername[10];
Guido van Rossumb6775db1994-08-01 11:34:53 +0000260 /* XXX This won't work on the southern hemisphere.
261 XXX Anybody got a better idea? */
Guido van Rossum234f9421993-06-17 12:35:49 +0000262 t = (time((time_t *)0) / YEAR) * YEAR;
263 p = localtime(&t);
264 winterzone = -p->tm_gmtoff;
265 strncpy(wintername, p->tm_zone ? p->tm_zone : " ", 9);
266 wintername[9] = '\0';
267 t += YEAR/2;
268 p = localtime(&t);
269 summerzone = -p->tm_gmtoff;
270 strncpy(summername, p->tm_zone ? p->tm_zone : " ", 9);
271 summername[9] = '\0';
272 dictinsert(d, "timezone", newintobject(winterzone));
273 dictinsert(d, "altzone", newintobject(summerzone));
274 dictinsert(d, "daylight",
275 newintobject((long)(winterzone != summerzone)));
276 dictinsert(d, "tzname",
277 mkvalue("(zz)", wintername, summername));
278 }
Guido van Rossumb6775db1994-08-01 11:34:53 +0000279#endif /* HAVE_TM_ZONE */
280#endif /* !HAVE_TZNAME */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000281}
282
283
Guido van Rossumb6775db1994-08-01 11:34:53 +0000284/* Implement floattime() for various platforms */
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000285
Guido van Rossumb6775db1994-08-01 11:34:53 +0000286static double
287floattime()
Guido van Rossum85a5fbb1990-10-14 12:07:46 +0000288{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000289 /* There are three ways to get the time:
290 (1) gettimeofday() -- resolution in microseconds
291 (2) ftime() -- resolution in milliseconds
292 (3) time() -- resolution in seconds
293 In all cases the return value is a float in seconds.
294 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
295 fail, so we fall back on ftime() or time().
296 Note: clock resolution does not imply clock accuracy! */
297#ifdef HAVE_GETTIMEOFDAY
298 {
Guido van Rossum426035c1991-02-19 12:27:35 +0000299 struct timeval t;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000300 if (gettimeofday(&t, (struct timezone *)NULL) == 0)
301 return (double)t.tv_sec + t.tv_usec*0.000001;
302 }
303#endif /* !HAVE_GETTIMEOFDAY */
304 {
305#ifdef HAVE_FTIME
306 struct timeb t;
307 ftime(&t);
308 return (double)t.time + t.millitm*0.001;
309#else /* !HAVE_FTIME */
310 time_t secs;
311 time(&secs);
312 return (double)secs;
313#endif /* !HAVE_FTIME */
314 }
Guido van Rossum426035c1991-02-19 12:27:35 +0000315}
316
Guido van Rossumb6775db1994-08-01 11:34:53 +0000317
318/* Implement floatsleep() for various platforms.
319 When interrupted (or when another error occurs), return -1 and
320 set an exception; else return 0. */
321
322static int
Guido van Rossum775f4da1993-01-09 17:18:52 +0000323floatsleep(secs)
324 double secs;
Guido van Rossum426035c1991-02-19 12:27:35 +0000325{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000326#ifdef HAVE_SELECT
Guido van Rossum426035c1991-02-19 12:27:35 +0000327 struct timeval t;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000328 double frac;
329 extern double fmod PROTO((double, double));
330 extern double floor PROTO((double));
331 frac = fmod(secs, 1.0);
332 secs = floor(secs);
333 t.tv_sec = (long)secs;
334 t.tv_usec = (long)(frac*1000000.0);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000335 if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
336 err_errno(IOError);
337 return -1;
338 }
339#else /* !HAVE_SELECT */
340#ifdef macintosh
341#define MacTicks (* (long *)0x16A)
342 long deadline;
343 deadline = MacTicks + (long)(secs * 60.0);
344 while (MacTicks < deadline) {
345 if (sigcheck())
346 return -1;
347 }
348#else /* !macintosh */
Guido van Rossume22e6441993-07-09 10:51:31 +0000349#ifdef MSDOS
Guido van Rossumb6775db1994-08-01 11:34:53 +0000350 struct timeb t1, t2;
351 double frac;
352 extern double fmod PROTO((double, double));
353 extern double floor PROTO((double));
354 if (secs <= 0.0)
355 return;
356 frac = fmod(secs, 1.0);
357 secs = floor(secs);
358 ftime(&t1);
359 t2.time = t1.time + (int)secs;
360 t2.millitm = t1.millitm + (int)(frac*1000.0);
361 while (t2.millitm >= 1000) {
362 t2.time++;
363 t2.millitm -= 1000;
364 }
365 for (;;) {
366#ifdef QUICKWIN
367 _wyield();
Guido van Rossum80c9d881991-04-16 08:47:51 +0000368#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000369 if (sigcheck())
370 return -1;
371 ftime(&t1);
372 if (t1.time > t2.time ||
373 t1.time == t2.time && t1.millitm >= t2.millitm)
374 break;
375 }
376#else /* !MSDOS */
377#ifdef _M_IX86
378 /* XXX Can't interrupt this sleep */
379 Sleep((int)(secs*1000));
380#else /* _M_IX86 */
381 /* XXX Can't interrupt this sleep */
382 sleep((int)secs);
383#endif /* _M_IX86 */
384#endif /* !MSDOS */
385#endif /* !macintosh */
386#endif /* !HAVE_SELECT */
387 return 0;
Guido van Rossum80c9d881991-04-16 08:47:51 +0000388}