timemodule.c revision e6a4b7bf3eaf299ec8765b4bec74bf4c7f4db60f
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>
62#ifndef MS_WINDOWS
63extern int ftime();
64#endif /* MS_WINDOWS */
65#endif /* HAVE_FTIME */
66
67#ifdef __WATCOMC__
68#include <i86.h>
69#else
70#ifdef MS_WINDOWS
71#include <windows.h>
72#ifdef MS_WIN16
73/* These overrides not needed for Win32 */
74#define timezone _timezone
75#define tzname _tzname
76#define daylight _daylight
77#define altzone _altzone
78#endif /* MS_WIN16 */
79#endif /* MS_WINDOWS */
80#endif /* !__WATCOMC__ */
81
82#ifdef MS_WIN32
83/* Win32 has better clock replacement */
84#include <largeint.h>
85#undef HAVE_CLOCK /* We have our own version down below */
86#endif /* MS_WIN32 */
87
88/* Forward declarations */
89static int floatsleep Py_PROTO((double));
90static double floattime Py_PROTO(());
91
92#ifdef macintosh
93/* Our own timezone. We have enough information to deduce whether
94** DST is on currently, but unfortunately we cannot put it to good
95** use because we don't know the rules (and that is needed to have
96** localtime() return correct tm_isdst values for times other than
97** the current time. So, we cop out and only tell the user the current
98** timezone.
99*/
100static long timezone;
101
102static void
103initmactimezone()
104{
105	MachineLocation	loc;
106	long		delta;
107
108	ReadLocation(&loc);
109
110	if (loc.latitude == 0 && loc.longitude == 0 && loc.u.gmtDelta == 0)
111		return;
112
113	delta = loc.u.gmtDelta & 0x00FFFFFF;
114
115	if (delta & 0x00800000)
116		delta |= 0xFF000000;
117
118	timezone = -delta;
119}
120#endif /* macintosh */
121
122
123static PyObject *
124time_time(self, args)
125	PyObject *self;
126	PyObject *args;
127{
128	double secs;
129	if (!PyArg_NoArgs(args))
130		return NULL;
131	secs = floattime();
132	if (secs == 0.0) {
133		PyErr_SetFromErrno(PyExc_IOError);
134		return NULL;
135	}
136	return PyFloat_FromDouble(secs);
137}
138
139#ifdef HAVE_CLOCK
140
141#ifndef CLOCKS_PER_SEC
142#ifdef CLK_TCK
143#define CLOCKS_PER_SEC CLK_TCK
144#else
145#define CLOCKS_PER_SEC 1000000
146#endif
147#endif
148
149static PyObject *
150time_clock(self, args)
151	PyObject *self;
152	PyObject *args;
153{
154	if (!PyArg_NoArgs(args))
155		return NULL;
156	return PyFloat_FromDouble(((double)clock()) / CLOCKS_PER_SEC);
157}
158#endif /* HAVE_CLOCK */
159
160#ifdef MS_WIN32
161/* Due to Mark Hammond */
162static PyObject *
163time_clock(self, args)
164	PyObject *self;
165	PyObject *args;
166{
167	static LARGE_INTEGER ctrStart;
168	static LARGE_INTEGER divisor = {0,0};
169	LARGE_INTEGER now, diff, rem;
170
171	if (!PyArg_NoArgs(args))
172		return NULL;
173
174	if (LargeIntegerEqualToZero(divisor)) {
175		QueryPerformanceCounter(&ctrStart);
176		if (!QueryPerformanceFrequency(&divisor) ||
177		    LargeIntegerEqualToZero(divisor)) {
178				/* Unlikely to happen -
179				   this works on all intel machines at least!
180				   Revert to clock() */
181			return PyFloat_FromDouble(clock());
182		}
183	}
184	QueryPerformanceCounter(&now);
185	diff = LargeIntegerSubtract(now, ctrStart);
186	diff = LargeIntegerDivide(diff, divisor, &rem);
187	/* XXX - we assume both divide results fit in 32 bits.  This is
188	   true on Intels.  First person who can afford a machine that
189	   doesnt deserves to fix it :-)
190	*/
191	return PyFloat_FromDouble((double)diff.LowPart +
192		              ((double)rem.LowPart / (double)divisor.LowPart));
193}
194#define HAVE_CLOCK /* So it gets included in the methods */
195#endif /* MS_WIN32 */
196
197static PyObject *
198time_sleep(self, args)
199	PyObject *self;
200	PyObject *args;
201{
202	double secs;
203	if (!PyArg_Parse(args, "d", &secs))
204		return NULL;
205	Py_BEGIN_ALLOW_THREADS
206		if (floatsleep(secs) != 0) {
207			Py_BLOCK_THREADS
208			return NULL;
209		}
210	Py_END_ALLOW_THREADS
211		Py_INCREF(Py_None);
212	return Py_None;
213}
214
215static PyObject *
216time_convert(when, function)
217	time_t when;
218	struct tm * (*function) Py_PROTO((const time_t *));
219{
220	struct tm *p;
221	errno = 0;
222	p = function(&when);
223	if (p == NULL) {
224#ifdef EINVAL
225		if (errno == 0)
226			errno = EINVAL;
227#endif
228		return PyErr_SetFromErrno(PyExc_IOError);
229	}
230	return Py_BuildValue("(iiiiiiiii)",
231			     p->tm_year + 1900,
232			     p->tm_mon + 1,        /* Want January == 1 */
233			     p->tm_mday,
234			     p->tm_hour,
235			     p->tm_min,
236			     p->tm_sec,
237			     (p->tm_wday + 6) % 7, /* Want Monday == 0 */
238			     p->tm_yday + 1,       /* Want January, 1 == 1 */
239			     p->tm_isdst);
240}
241
242static PyObject *
243time_gmtime(self, args)
244	PyObject *self;
245	PyObject *args;
246{
247	double when;
248	if (!PyArg_Parse(args, "d", &when))
249		return NULL;
250	return time_convert((time_t)when, gmtime);
251}
252
253static PyObject *
254time_localtime(self, args)
255	PyObject *self;
256	PyObject *args;
257{
258	double when;
259	if (!PyArg_Parse(args, "d", &when))
260		return NULL;
261	return time_convert((time_t)when, localtime);
262}
263
264static int
265gettmarg(args, p)
266	PyObject *args;
267	struct tm *p;
268{
269	if (!PyArg_Parse(args, "(iiiiiiiii)",
270			 &p->tm_year,
271			 &p->tm_mon,
272			 &p->tm_mday,
273			 &p->tm_hour,
274			 &p->tm_min,
275			 &p->tm_sec,
276			 &p->tm_wday,
277			 &p->tm_yday,
278			 &p->tm_isdst))
279		return 0;
280	if (p->tm_year >= 1900)
281		p->tm_year -= 1900;
282	p->tm_mon--;
283	p->tm_wday = (p->tm_wday + 1) % 7;
284	p->tm_yday--;
285	return 1;
286}
287
288#ifdef HAVE_STRFTIME
289static PyObject *
290time_strftime(self, args)
291	PyObject *self;
292	PyObject *args;
293{
294	struct tm buf;
295	const char *fmt;
296	char *outbuf = 0;
297	int i;
298
299	if (!PyArg_ParseTuple(args, "s(iiiiiiiii)",
300			      &fmt,
301			      &(buf.tm_year),
302			      &(buf.tm_mon),
303			      &(buf.tm_mday),
304			      &(buf.tm_hour),
305			      &(buf.tm_min),
306			      &(buf.tm_sec),
307			      &(buf.tm_wday),
308			      &(buf.tm_yday),
309			      &(buf.tm_isdst)))
310		return NULL;
311	if (buf.tm_year >= 1900)
312		buf.tm_year -= 1900;
313	buf.tm_mon--;
314	buf.tm_wday = (buf.tm_wday + 1) % 7;
315	buf.tm_yday--;
316	/* I hate these functions that presume you know how big the output
317	 * will be ahead of time...
318	 */
319	for (i = 1024 ; i <= 8192 ; i += 1024) {
320		outbuf = malloc(i);
321		if (outbuf == NULL) {
322			return PyErr_NoMemory();
323		}
324		if (strftime(outbuf, i-1, fmt, &buf) != 0) {
325			PyObject *ret;
326			ret = PyString_FromString(outbuf);
327			free(outbuf);
328			return ret;
329		}
330		free(outbuf);
331	}
332	PyErr_SetString(PyExc_ValueError,
333			"bad strftime format or result too big");
334	return NULL;
335}
336#endif /* HAVE_STRFTIME */
337
338static PyObject *
339time_asctime(self, args)
340	PyObject *self;
341	PyObject *args;
342{
343	struct tm buf;
344	char *p;
345	if (!gettmarg(args, &buf))
346		return NULL;
347	p = asctime(&buf);
348	if (p[24] == '\n')
349		p[24] = '\0';
350	return PyString_FromString(p);
351}
352
353static PyObject *
354time_ctime(self, args)
355	PyObject *self;
356	PyObject *args;
357{
358	double dt;
359	time_t tt;
360	char *p;
361	if (!PyArg_Parse(args, "d", &dt))
362		return NULL;
363	tt = (time_t)dt;
364	p = ctime(&tt);
365	if (p[24] == '\n')
366		p[24] = '\0';
367	return PyString_FromString(p);
368}
369
370static PyObject *
371time_mktime(self, args)
372	PyObject *self;
373	PyObject *args;
374{
375	struct tm buf;
376	time_t tt;
377	tt = time(&tt);
378	buf = *localtime(&tt);
379	if (!gettmarg(args, &buf))
380		return NULL;
381	tt = mktime(&buf);
382	if (tt == (time_t)(-1)) {
383		PyErr_SetString(PyExc_OverflowError,
384                                "mktime argument out of range");
385		return NULL;
386	}
387	return PyFloat_FromDouble((double)tt);
388}
389
390static PyMethodDef time_methods[] = {
391	{"time",	time_time},
392#ifdef HAVE_CLOCK
393	{"clock",	time_clock},
394#endif
395	{"sleep",	time_sleep},
396	{"gmtime",	time_gmtime},
397	{"localtime",	time_localtime},
398	{"asctime",	time_asctime},
399	{"ctime",	time_ctime},
400	{"mktime",	time_mktime},
401#ifdef HAVE_STRFTIME
402	{"strftime",	time_strftime, 1},
403#endif
404	{NULL,		NULL}		/* sentinel */
405};
406
407static void
408ins(d, name, v)
409	PyObject *d;
410	char *name;
411	PyObject *v;
412{
413	if (v == NULL)
414		Py_FatalError("Can't initialize time module -- NULL value");
415	if (PyDict_SetItemString(d, name, v) != 0)
416		Py_FatalError(
417		"Can't initialize time module -- PyDict_SetItemString failed");
418	Py_DECREF(v);
419}
420
421void
422inittime()
423{
424	PyObject *m, *d;
425	m = Py_InitModule("time", time_methods);
426	d = PyModule_GetDict(m);
427#ifdef HAVE_TZNAME
428	tzset();
429	ins(d, "timezone", PyInt_FromLong((long)timezone));
430#ifdef HAVE_ALTZONE
431	ins(d, "altzone", PyInt_FromLong((long)altzone));
432#else
433	ins(d, "altzone", PyInt_FromLong((long)timezone-3600));
434#endif
435	ins(d, "daylight", PyInt_FromLong((long)daylight));
436	ins(d, "tzname", Py_BuildValue("(zz)", tzname[0], tzname[1]));
437#else /* !HAVE_TZNAME */
438#if HAVE_TM_ZONE
439	{
440#define YEAR ((time_t)((365 * 24 + 6) * 3600))
441		time_t t;
442		struct tm *p;
443		long winterzone, summerzone;
444		char wintername[10], summername[10];
445		/* XXX This won't work on the southern hemisphere.
446		  XXX Anybody got a better idea? */
447		t = (time((time_t *)0) / YEAR) * YEAR;
448		p = localtime(&t);
449		winterzone = -p->tm_gmtoff;
450		strncpy(wintername, p->tm_zone ? p->tm_zone : "   ", 9);
451		wintername[9] = '\0';
452		t += YEAR/2;
453		p = localtime(&t);
454		summerzone = -p->tm_gmtoff;
455		strncpy(summername, p->tm_zone ? p->tm_zone : "   ", 9);
456		summername[9] = '\0';
457		ins(d, "timezone", PyInt_FromLong(winterzone));
458		ins(d, "altzone", PyInt_FromLong(summerzone));
459		ins(d, "daylight",
460                    PyInt_FromLong((long)(winterzone != summerzone)));
461		ins(d, "tzname",
462                    Py_BuildValue("(zz)", wintername, summername));
463	}
464#else
465#ifdef macintosh
466	initmactimezone();
467	ins(d, "timezone", PyInt_FromLong(timezone));
468#endif /* macintosh */
469#endif /* HAVE_TM_ZONE */
470#endif /* !HAVE_TZNAME */
471	if (PyErr_Occurred())
472		Py_FatalError("Can't initialize time module");
473}
474
475
476/* Implement floattime() for various platforms */
477
478static double
479floattime()
480{
481	/* There are three ways to get the time:
482	  (1) gettimeofday() -- resolution in microseconds
483	  (2) ftime() -- resolution in milliseconds
484	  (3) time() -- resolution in seconds
485	  In all cases the return value is a float in seconds.
486	  Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
487	  fail, so we fall back on ftime() or time().
488	  Note: clock resolution does not imply clock accuracy! */
489#ifdef HAVE_GETTIMEOFDAY
490	{
491		struct timeval t;
492#ifdef GETTIMEOFDAY_NO_TZ
493		if (gettimeofday(&t) == 0)
494			return (double)t.tv_sec + t.tv_usec*0.000001;
495#else /* !GETTIMEOFDAY_NO_TZ */
496		if (gettimeofday(&t, (struct timezone *)NULL) == 0)
497			return (double)t.tv_sec + t.tv_usec*0.000001;
498#endif /* !GETTIMEOFDAY_NO_TZ */
499	}
500#endif /* !HAVE_GETTIMEOFDAY */
501	{
502#ifdef HAVE_FTIME
503		struct timeb t;
504		ftime(&t);
505		return (double)t.time + (double)t.millitm * (double)0.001;
506#else /* !HAVE_FTIME */
507		time_t secs;
508		time(&secs);
509		return (double)secs;
510#endif /* !HAVE_FTIME */
511	}
512}
513
514
515/* Implement floatsleep() for various platforms.
516   When interrupted (or when another error occurs), return -1 and
517   set an exception; else return 0. */
518
519static int
520#ifdef MPW
521floatsleep(double secs)
522#else
523	floatsleep(secs)
524	double secs;
525#endif /* MPW */
526{
527/* XXX Should test for MS_WIN32 first! */
528#ifdef HAVE_SELECT
529	struct timeval t;
530	double frac;
531	frac = fmod(secs, 1.0);
532	secs = floor(secs);
533	t.tv_sec = (long)secs;
534	t.tv_usec = (long)(frac*1000000.0);
535	if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
536		PyErr_SetFromErrno(PyExc_IOError);
537		return -1;
538	}
539#else /* !HAVE_SELECT */
540#ifdef macintosh
541#define MacTicks	(* (long *)0x16A)
542	long deadline;
543	deadline = MacTicks + (long)(secs * 60.0);
544	while (MacTicks < deadline) {
545		if (PyErr_CheckSignals())
546			return -1;
547	}
548#else /* !macintosh */
549#ifdef __WATCOMC__
550	/* XXX Can't interrupt this sleep */
551	delay((int)(secs * 1000 + 0.5));  /* delay() uses milliseconds */
552#else /* !__WATCOMC__ */
553#ifdef MSDOS
554	struct timeb t1, t2;
555	double frac;
556	extern double fmod Py_PROTO((double, double));
557	extern double floor Py_PROTO((double));
558	if (secs <= 0.0)
559		return;
560	frac = fmod(secs, 1.0);
561	secs = floor(secs);
562	ftime(&t1);
563	t2.time = t1.time + (int)secs;
564	t2.millitm = t1.millitm + (int)(frac*1000.0);
565	while (t2.millitm >= 1000) {
566		t2.time++;
567		t2.millitm -= 1000;
568	}
569	for (;;) {
570#ifdef QUICKWIN
571		_wyield();
572#endif
573		if (PyErr_CheckSignals())
574			return -1;
575		ftime(&t1);
576		if (t1.time > t2.time ||
577		    t1.time == t2.time && t1.millitm >= t2.millitm)
578			break;
579	}
580#else /* !MSDOS */
581#ifdef MS_WIN32
582	/* XXX Can't interrupt this sleep */
583	Sleep((int)(secs*1000));
584#else /* !MS_WIN32 */
585	/* XXX Can't interrupt this sleep */
586	sleep((int)secs);
587#endif /* !MS_WIN32 */
588#endif /* !MSDOS */
589#endif /* !__WATCOMC__ */
590#endif /* !macintosh */
591#endif /* !HAVE_SELECT */
592	return 0;
593}
594