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