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