blob: 6caa37f2f594885a02a2ab2a2bc76c87a87ca9b4 [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 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 Rossum3bbc62e1995-01-02 19:30:30 +0000300#ifdef GETTIMEOFDAY_NO_TZ
301 if (gettimeofday(&t) == 0)
302 return (double)t.tv_sec + t.tv_usec*0.000001;
303#else /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000304 if (gettimeofday(&t, (struct timezone *)NULL) == 0)
305 return (double)t.tv_sec + t.tv_usec*0.000001;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000306#endif /* !GETTIMEOFDAY_NO_TZ */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000307 }
308#endif /* !HAVE_GETTIMEOFDAY */
309 {
310#ifdef HAVE_FTIME
311 struct timeb t;
312 ftime(&t);
Guido van Rossum7b1e9741994-08-29 10:46:42 +0000313 return (double)t.time + (double)t.millitm * (double)0.001;
Guido van Rossumb6775db1994-08-01 11:34:53 +0000314#else /* !HAVE_FTIME */
315 time_t secs;
316 time(&secs);
317 return (double)secs;
318#endif /* !HAVE_FTIME */
319 }
Guido van Rossum426035c1991-02-19 12:27:35 +0000320}
321
Guido van Rossumb6775db1994-08-01 11:34:53 +0000322
323/* Implement floatsleep() for various platforms.
324 When interrupted (or when another error occurs), return -1 and
325 set an exception; else return 0. */
326
327static int
Guido van Rossum775f4da1993-01-09 17:18:52 +0000328floatsleep(secs)
329 double secs;
Guido van Rossum426035c1991-02-19 12:27:35 +0000330{
Guido van Rossumb6775db1994-08-01 11:34:53 +0000331#ifdef HAVE_SELECT
Guido van Rossum426035c1991-02-19 12:27:35 +0000332 struct timeval t;
Guido van Rossum775f4da1993-01-09 17:18:52 +0000333 double frac;
334 extern double fmod PROTO((double, double));
335 extern double floor PROTO((double));
336 frac = fmod(secs, 1.0);
337 secs = floor(secs);
338 t.tv_sec = (long)secs;
339 t.tv_usec = (long)(frac*1000000.0);
Guido van Rossumb6775db1994-08-01 11:34:53 +0000340 if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
341 err_errno(IOError);
342 return -1;
343 }
344#else /* !HAVE_SELECT */
345#ifdef macintosh
346#define MacTicks (* (long *)0x16A)
347 long deadline;
348 deadline = MacTicks + (long)(secs * 60.0);
349 while (MacTicks < deadline) {
350 if (sigcheck())
351 return -1;
352 }
353#else /* !macintosh */
Guido van Rossume22e6441993-07-09 10:51:31 +0000354#ifdef MSDOS
Guido van Rossumb6775db1994-08-01 11:34:53 +0000355 struct timeb t1, t2;
356 double frac;
357 extern double fmod PROTO((double, double));
358 extern double floor PROTO((double));
359 if (secs <= 0.0)
360 return;
361 frac = fmod(secs, 1.0);
362 secs = floor(secs);
363 ftime(&t1);
364 t2.time = t1.time + (int)secs;
365 t2.millitm = t1.millitm + (int)(frac*1000.0);
366 while (t2.millitm >= 1000) {
367 t2.time++;
368 t2.millitm -= 1000;
369 }
370 for (;;) {
371#ifdef QUICKWIN
372 _wyield();
Guido van Rossum80c9d881991-04-16 08:47:51 +0000373#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +0000374 if (sigcheck())
375 return -1;
376 ftime(&t1);
377 if (t1.time > t2.time ||
378 t1.time == t2.time && t1.millitm >= t2.millitm)
379 break;
380 }
381#else /* !MSDOS */
382#ifdef _M_IX86
383 /* XXX Can't interrupt this sleep */
384 Sleep((int)(secs*1000));
385#else /* _M_IX86 */
386 /* XXX Can't interrupt this sleep */
387 sleep((int)secs);
388#endif /* _M_IX86 */
389#endif /* !MSDOS */
390#endif /* !macintosh */
391#endif /* !HAVE_SELECT */
392 return 0;
Guido van Rossum80c9d881991-04-16 08:47:51 +0000393}