timemodule.c revision ec775c52a26cf4b1090e7038dfe4f999378ac9c8
1/***********************************************************
2Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
4
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 or Corporation for National Research Initiatives or
13CNRI not be used in advertising or publicity pertaining to
14distribution of the software without specific, written prior
15permission.
16
17While CWI is the initial source for this software, a modified version
18is made available by the Corporation for National Research Initiatives
19(CNRI) at the Internet address ftp://ftp.python.org.
20
21STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28PERFORMANCE OF THIS SOFTWARE.
29
30******************************************************************/
31
32/* Time module */
33
34#include "Python.h"
35
36#ifdef HAVE_SELECT
37#include "mymath.h"
38#endif
39
40#ifdef macintosh
41#include <time.h>
42#else
43#include <sys/types.h>
44#endif
45
46#ifdef QUICKWIN
47#include <io.h>
48#endif
49
50#ifdef HAVE_UNISTD_H
51#include <unistd.h>
52#endif
53
54#ifdef HAVE_SELECT
55#include "myselect.h"
56#else
57#include "mytime.h"
58#endif
59
60#ifdef HAVE_FTIME
61#include <sys/timeb.h>
62extern int ftime();
63#endif
64
65#ifdef __WATCOMC__
66#include <i86.h>
67#else
68#ifdef MS_WINDOWS
69#include <windows.h>
70#ifdef MS_WIN16
71/* These overrides not needed for Win32 */
72#define timezone _timezone
73#define tzname _tzname
74#define daylight _daylight
75#define altzone _altzone
76#endif /* MS_WIN16 */
77#endif /* MS_WINDOWS */
78#endif /* !__WATCOMC__ */
79
80/* Forward declarations */
81static int floatsleep Py_PROTO((double));
82static double floattime Py_PROTO(());
83
84static PyObject *
85time_time(self, args)
86	PyObject *self;
87	PyObject *args;
88{
89	double secs;
90	if (!PyArg_NoArgs(args))
91		return NULL;
92	secs = floattime();
93	if (secs == 0.0) {
94		PyErr_SetFromErrno(PyExc_IOError);
95		return NULL;
96	}
97	return PyFloat_FromDouble(secs);
98}
99
100#ifdef HAVE_CLOCK
101
102#ifndef CLOCKS_PER_SEC
103#ifdef CLK_TCK
104#define CLOCKS_PER_SEC CLK_TCK
105#else
106#define CLOCKS_PER_SEC 1000000
107#endif
108#endif
109
110static PyObject *
111time_clock(self, args)
112	PyObject *self;
113	PyObject *args;
114{
115	if (!PyArg_NoArgs(args))
116		return NULL;
117	return PyFloat_FromDouble(((double)clock()) / CLOCKS_PER_SEC);
118}
119#endif /* HAVE_CLOCK */
120
121static PyObject *
122time_sleep(self, args)
123	PyObject *self;
124	PyObject *args;
125{
126	double secs;
127	if (!PyArg_Parse(args, "d", &secs))
128		return NULL;
129	Py_BEGIN_ALLOW_THREADS
130	if (floatsleep(secs) != 0) {
131		Py_BLOCK_THREADS
132		return NULL;
133	}
134	Py_END_ALLOW_THREADS
135	Py_INCREF(Py_None);
136	return Py_None;
137}
138
139static PyObject *
140time_convert(when, function)
141	time_t when;
142	struct tm * (*function) Py_PROTO((const time_t *));
143{
144	struct tm *p;
145	errno = 0;
146	p = function(&when);
147	if (p == NULL) {
148#ifdef EINVAL
149		if (errno == 0)
150			errno = EINVAL;
151#endif
152		return PyErr_SetFromErrno(PyExc_IOError);
153	}
154	return Py_BuildValue("(iiiiiiiii)",
155		       p->tm_year + 1900,
156		       p->tm_mon + 1,        /* Want January == 1 */
157		       p->tm_mday,
158		       p->tm_hour,
159		       p->tm_min,
160		       p->tm_sec,
161		       (p->tm_wday + 6) % 7, /* Want Monday == 0 */
162		       p->tm_yday + 1,       /* Want January, 1 == 1 */
163		       p->tm_isdst);
164}
165
166static PyObject *
167time_gmtime(self, args)
168	PyObject *self;
169	PyObject *args;
170{
171	double when;
172	if (!PyArg_Parse(args, "d", &when))
173		return NULL;
174	return time_convert((time_t)when, gmtime);
175}
176
177static PyObject *
178time_localtime(self, args)
179	PyObject *self;
180	PyObject *args;
181{
182	double when;
183	if (!PyArg_Parse(args, "d", &when))
184		return NULL;
185	return time_convert((time_t)when, localtime);
186}
187
188static int
189gettmarg(args, p)
190	PyObject *args;
191	struct tm *p;
192{
193	if (!PyArg_Parse(args, "(iiiiiiiii)",
194		     &p->tm_year,
195		     &p->tm_mon,
196		     &p->tm_mday,
197		     &p->tm_hour,
198		     &p->tm_min,
199		     &p->tm_sec,
200		     &p->tm_wday,
201		     &p->tm_yday,
202		     &p->tm_isdst))
203		return 0;
204	if (p->tm_year >= 1900)
205		p->tm_year -= 1900;
206	p->tm_mon--;
207	p->tm_wday = (p->tm_wday + 1) % 7;
208	p->tm_yday--;
209	return 1;
210}
211
212#ifdef HAVE_STRFTIME
213static PyObject *
214time_strftime(self, args)
215	PyObject *self;
216	PyObject *args;
217{
218	struct tm buf;
219	const char *fmt;
220	char *outbuf = 0;
221	int i;
222
223	if (!PyArg_ParseTuple(args, "s(iiiiiiiii)",
224			      &fmt,
225			      &(buf.tm_year),
226			      &(buf.tm_mon),
227			      &(buf.tm_mday),
228			      &(buf.tm_hour),
229			      &(buf.tm_min),
230			      &(buf.tm_sec),
231			      &(buf.tm_wday),
232			      &(buf.tm_yday),
233			      &(buf.tm_isdst)))
234		return NULL;
235	if (buf.tm_year >= 1900)
236		buf.tm_year -= 1900;
237	buf.tm_mon--;
238	buf.tm_wday = (buf.tm_wday + 1) % 7;
239	buf.tm_yday--;
240	/* I hate these functions that presume you know how big the output */
241	/* will be ahead of time... */
242	for (i = 1024 ; i < 8192 ; i += 1024) {
243		outbuf = malloc(i);
244		if (outbuf == NULL) {
245			return PyErr_NoMemory();
246		}
247		if (strftime(outbuf, i-1, fmt, &buf) != 0) {
248			PyObject *ret;
249			ret = PyString_FromString(outbuf);
250			free(outbuf);
251			return ret;
252		}
253		free(outbuf);
254	}
255	return PyErr_NoMemory();
256}
257#endif /* HAVE_STRFTIME */
258
259static PyObject *
260time_asctime(self, args)
261	PyObject *self;
262	PyObject *args;
263{
264	struct tm buf;
265	char *p;
266	if (!gettmarg(args, &buf))
267		return NULL;
268	p = asctime(&buf);
269	if (p[24] == '\n')
270		p[24] = '\0';
271	return PyString_FromString(p);
272}
273
274static PyObject *
275time_ctime(self, args)
276	PyObject *self;
277	PyObject *args;
278{
279	double dt;
280	time_t tt;
281	char *p;
282	if (!PyArg_Parse(args, "d", &dt))
283		return NULL;
284	tt = (time_t)dt;
285	p = ctime(&tt);
286	if (p[24] == '\n')
287		p[24] = '\0';
288	return PyString_FromString(p);
289}
290
291static PyObject *
292time_mktime(self, args)
293	PyObject *self;
294	PyObject *args;
295{
296	struct tm buf;
297	time_t tt;
298	tt = time(&tt);
299	buf = *localtime(&tt);
300	if (!gettmarg(args, &buf))
301		return NULL;
302	tt = mktime(&buf);
303	if (tt == (time_t)(-1)) {
304		PyErr_SetString(PyExc_OverflowError,
305                                "mktime argument out of range");
306		return NULL;
307	}
308	return PyFloat_FromDouble((double)tt);
309}
310
311static PyMethodDef time_methods[] = {
312	{"time",	time_time},
313#ifdef HAVE_CLOCK
314	{"clock",	time_clock},
315#endif
316	{"sleep",	time_sleep},
317	{"gmtime",	time_gmtime},
318	{"localtime",	time_localtime},
319	{"asctime",	time_asctime},
320	{"ctime",	time_ctime},
321	{"mktime",	time_mktime},
322#ifdef HAVE_STRFTIME
323	{"strftime",	time_strftime, 1},
324#endif
325	{NULL,		NULL}		/* sentinel */
326};
327
328static void
329ins(d, name, v)
330	PyObject *d;
331	char *name;
332	PyObject *v;
333{
334	if (v == NULL)
335		Py_FatalError("Can't initialize time module -- NULL value");
336	if (PyDict_SetItemString(d, name, v) != 0)
337		Py_FatalError(
338                        "Can't initialize time module -- PyDict_SetItemString failed");
339	Py_DECREF(v);
340}
341
342void
343inittime()
344{
345	PyObject *m, *d;
346	m = Py_InitModule("time", time_methods);
347	d = PyModule_GetDict(m);
348#ifdef HAVE_TZNAME
349	tzset();
350	ins(d, "timezone", PyInt_FromLong((long)timezone));
351#ifdef HAVE_ALTZONE
352	ins(d, "altzone", PyInt_FromLong((long)altzone));
353#else
354	ins(d, "altzone", PyInt_FromLong((long)timezone-3600));
355#endif
356	ins(d, "daylight", PyInt_FromLong((long)daylight));
357	ins(d, "tzname", Py_BuildValue("(zz)", tzname[0], tzname[1]));
358#else /* !HAVE_TZNAME */
359#if HAVE_TM_ZONE
360	{
361#define YEAR ((time_t)((365 * 24 + 6) * 3600))
362		time_t t;
363		struct tm *p;
364		long winterzone, summerzone;
365		char wintername[10], summername[10];
366		/* XXX This won't work on the southern hemisphere.
367		   XXX Anybody got a better idea? */
368		t = (time((time_t *)0) / YEAR) * YEAR;
369		p = localtime(&t);
370		winterzone = -p->tm_gmtoff;
371		strncpy(wintername, p->tm_zone ? p->tm_zone : "   ", 9);
372		wintername[9] = '\0';
373		t += YEAR/2;
374		p = localtime(&t);
375		summerzone = -p->tm_gmtoff;
376		strncpy(summername, p->tm_zone ? p->tm_zone : "   ", 9);
377		summername[9] = '\0';
378		ins(d, "timezone", PyInt_FromLong(winterzone));
379		ins(d, "altzone", PyInt_FromLong(summerzone));
380		ins(d, "daylight",
381                    PyInt_FromLong((long)(winterzone != summerzone)));
382		ins(d, "tzname",
383                    Py_BuildValue("(zz)", wintername, summername));
384	}
385#endif /* HAVE_TM_ZONE */
386#endif /* !HAVE_TZNAME */
387}
388
389
390/* Implement floattime() for various platforms */
391
392static double
393floattime()
394{
395	/* There are three ways to get the time:
396	   (1) gettimeofday() -- resolution in microseconds
397	   (2) ftime() -- resolution in milliseconds
398	   (3) time() -- resolution in seconds
399	   In all cases the return value is a float in seconds.
400	   Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
401	   fail, so we fall back on ftime() or time().
402	   Note: clock resolution does not imply clock accuracy! */
403#ifdef HAVE_GETTIMEOFDAY
404    {
405	struct timeval t;
406#ifdef GETTIMEOFDAY_NO_TZ
407	if (gettimeofday(&t) == 0)
408		return (double)t.tv_sec + t.tv_usec*0.000001;
409#else /* !GETTIMEOFDAY_NO_TZ */
410	if (gettimeofday(&t, (struct timezone *)NULL) == 0)
411		return (double)t.tv_sec + t.tv_usec*0.000001;
412#endif /* !GETTIMEOFDAY_NO_TZ */
413    }
414#endif /* !HAVE_GETTIMEOFDAY */
415    {
416#ifdef HAVE_FTIME
417	struct timeb t;
418	ftime(&t);
419	return (double)t.time + (double)t.millitm * (double)0.001;
420#else /* !HAVE_FTIME */
421	time_t secs;
422	time(&secs);
423	return (double)secs;
424#endif /* !HAVE_FTIME */
425    }
426}
427
428
429/* Implement floatsleep() for various platforms.
430   When interrupted (or when another error occurs), return -1 and
431   set an exception; else return 0. */
432
433static int
434#ifdef MPW
435floatsleep(double secs)
436#else
437floatsleep(secs)
438	double secs;
439#endif /* MPW */
440{
441#ifdef HAVE_SELECT
442	struct timeval t;
443	double frac;
444	frac = fmod(secs, 1.0);
445	secs = floor(secs);
446	t.tv_sec = (long)secs;
447	t.tv_usec = (long)(frac*1000000.0);
448	if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
449		PyErr_SetFromErrno(PyExc_IOError);
450		return -1;
451	}
452#else /* !HAVE_SELECT */
453#ifdef macintosh
454#define MacTicks	(* (long *)0x16A)
455	long deadline;
456	deadline = MacTicks + (long)(secs * 60.0);
457	while (MacTicks < deadline) {
458		if (PyErr_CheckSignals())
459			return -1;
460	}
461#else /* !macintosh */
462#ifdef __WATCOMC__
463	/* XXX Can't interrupt this sleep */
464	delay((int)(secs * 1000 + 0.5));  /* delay() uses milliseconds */
465#else /* !__WATCOMC__ */
466#ifdef MSDOS
467	struct timeb t1, t2;
468	double frac;
469	extern double fmod Py_PROTO((double, double));
470	extern double floor Py_PROTO((double));
471	if (secs <= 0.0)
472		return;
473	frac = fmod(secs, 1.0);
474	secs = floor(secs);
475	ftime(&t1);
476	t2.time = t1.time + (int)secs;
477	t2.millitm = t1.millitm + (int)(frac*1000.0);
478	while (t2.millitm >= 1000) {
479		t2.time++;
480		t2.millitm -= 1000;
481	}
482	for (;;) {
483#ifdef QUICKWIN
484		_wyield();
485#endif
486		if (PyErr_CheckSignals())
487			return -1;
488		ftime(&t1);
489		if (t1.time > t2.time ||
490		    t1.time == t2.time && t1.millitm >= t2.millitm)
491			break;
492	}
493#else /* !MSDOS */
494#ifdef MS_WIN32
495	/* XXX Can't interrupt this sleep */
496	Sleep((int)(secs*1000));
497#else /* !MS_WIN32 */
498	/* XXX Can't interrupt this sleep */
499	sleep((int)secs);
500#endif /* !MS_WIN32 */
501#endif /* !MSDOS */
502#endif /* !__WATCOMC__ */
503#endif /* !macintosh */
504#endif /* !HAVE_SELECT */
505	return 0;
506}
507