From 23a8cad783fc1e7e418a79d1e8a8822d8f4a6225 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 7 Feb 2012 23:41:01 +0100 Subject: Issue #13845: time.time() now uses GetSystemTimeAsFileTime() instead of ftime() to have a resolution of 100 ns instead of 1 ms (the clock accuracy is between 0.5 ms and 15 ms). --- Python/pytime.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'Python/pytime.c') diff --git a/Python/pytime.c b/Python/pytime.c index 6fb7695911..bec1c713e6 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -1,7 +1,9 @@ #include "Python.h" +#ifdef MS_WINDOWS +#include +#endif -#ifdef __APPLE__ -#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_FTIME) +#if defined(__APPLE__) && defined(HAVE_GETTIMEOFDAY) && defined(HAVE_FTIME) /* * _PyTime_gettimeofday falls back to ftime when getttimeofday fails because the latter * might fail on some platforms. This fallback is unwanted on MacOSX because @@ -10,18 +12,30 @@ */ # undef HAVE_FTIME #endif -#endif -#ifdef HAVE_FTIME +#if defined(HAVE_FTIME) && !defined(MS_WINDOWS) #include -#if !defined(MS_WINDOWS) && !defined(PYOS_OS2) extern int ftime(struct timeb *); -#endif /* MS_WINDOWS */ -#endif /* HAVE_FTIME */ +#endif void _PyTime_gettimeofday(_PyTime_timeval *tp) { +#ifdef MS_WINDOWS + FILETIME system_time; + ULARGE_INTEGER large; + ULONGLONG microseconds; + + GetSystemTimeAsFileTime(&system_time); + large.u.LowPart = system_time.dwLowDateTime; + large.u.HighPart = system_time.dwHighDateTime; + /* 11,644,473,600,000,000: number of microseconds between + the 1st january 1601 and the 1st january 1970 (369 years + 89 leap + days). */ + microseconds = large.QuadPart / 10 - 11644473600000000; + tp->tv_sec = microseconds / 1000000; + tp->tv_usec = microseconds % 1000000; +#else /* There are three ways to get the time: (1) gettimeofday() -- resolution in microseconds (2) ftime() -- resolution in milliseconds @@ -30,6 +44,7 @@ _PyTime_gettimeofday(_PyTime_timeval *tp) Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may fail, so we fall back on ftime() or time(). Note: clock resolution does not imply clock accuracy! */ + #ifdef HAVE_GETTIMEOFDAY #ifdef GETTIMEOFDAY_NO_TZ if (gettimeofday(tp) == 0) @@ -39,6 +54,7 @@ _PyTime_gettimeofday(_PyTime_timeval *tp) return; #endif /* !GETTIMEOFDAY_NO_TZ */ #endif /* !HAVE_GETTIMEOFDAY */ + #if defined(HAVE_FTIME) { struct timeb t; @@ -50,7 +66,8 @@ _PyTime_gettimeofday(_PyTime_timeval *tp) tp->tv_sec = time(NULL); tp->tv_usec = 0; #endif /* !HAVE_FTIME */ - return; + +#endif /* MS_WINDOWS */ } void -- cgit v1.2.1 From 9444533c014ebfd2aed80f40ce8d15ce5c675a40 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 2 Mar 2012 22:54:03 +0100 Subject: Issue #13964: signal.sigtimedwait() timeout is now a float instead of a tuple Add a private API to convert an int or float to a C timespec structure. --- Python/pytime.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'Python/pytime.c') diff --git a/Python/pytime.c b/Python/pytime.c index bec1c713e6..d23ce75b43 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -70,6 +70,51 @@ _PyTime_gettimeofday(_PyTime_timeval *tp) #endif /* MS_WINDOWS */ } +int +_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec) +{ + if (PyFloat_Check(obj)) { + double d, intpart, floatpart, err; + + d = PyFloat_AsDouble(obj); + floatpart = modf(d, &intpart); + if (floatpart < 0) { + floatpart = 1.0 + floatpart; + intpart -= 1.0; + } + + *sec = (time_t)intpart; + err = intpart - (double)*sec; + if (err <= -1.0 || err >= 1.0) + goto overflow; + + floatpart *= 1e9; + *nsec = (long)floatpart; + return 0; + } + else { +#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG + *sec = PyLong_AsLongLong(obj); +#else + assert(sizeof(time_t) <= sizeof(long)); + *sec = PyLong_AsLong(obj); +#endif + if (*sec == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) + goto overflow; + else + return -1; + } + *nsec = 0; + return 0; + } + +overflow: + PyErr_SetString(PyExc_OverflowError, + "timestamp out of range for platform time_t"); + return -1; +} + void _PyTime_Init() { -- cgit v1.2.1 From adce5ff128974a4206a25388f449633c579d4e8a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 13 Mar 2012 13:35:55 +0100 Subject: Close #14180: Factorize code to convert a number of seconds to time_t, timeval or timespec time.ctime(), gmtime(), time.localtime(), datetime.date.fromtimestamp(), datetime.datetime.fromtimestamp() and datetime.datetime.utcfromtimestamp() now raises an OverflowError, instead of a ValueError, if the timestamp does not fit in time_t. datetime.datetime.fromtimestamp() and datetime.datetime.utcfromtimestamp() now round microseconds towards zero instead of rounding to nearest with ties going away from zero. --- Python/pytime.c | 99 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 22 deletions(-) (limited to 'Python/pytime.c') diff --git a/Python/pytime.c b/Python/pytime.c index d23ce75b43..79a1a33616 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -70,9 +70,37 @@ _PyTime_gettimeofday(_PyTime_timeval *tp) #endif /* MS_WINDOWS */ } -int -_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec) +static void +error_time_t_overflow(void) +{ + PyErr_SetString(PyExc_OverflowError, + "timestamp out of range for platform time_t"); +} + +static time_t +_PyLong_AsTime_t(PyObject *obj) +{ +#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG + PY_LONG_LONG val; + val = PyLong_AsLongLong(obj); +#else + long val; + assert(sizeof(time_t) <= sizeof(long)); + val = PyLong_AsLong(obj); +#endif + if (val == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) + error_time_t_overflow(); + return -1; + } + return (time_t)val; +} + +static int +_PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator, + double denominator) { + assert(denominator <= LONG_MAX); if (PyFloat_Check(obj)) { double d, intpart, floatpart, err; @@ -85,34 +113,61 @@ _PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec) *sec = (time_t)intpart; err = intpart - (double)*sec; - if (err <= -1.0 || err >= 1.0) - goto overflow; + if (err <= -1.0 || err >= 1.0) { + error_time_t_overflow(); + return -1; + } - floatpart *= 1e9; - *nsec = (long)floatpart; + floatpart *= denominator; + *numerator = (long)floatpart; return 0; } else { -#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG - *sec = PyLong_AsLongLong(obj); -#else - assert(sizeof(time_t) <= sizeof(long)); - *sec = PyLong_AsLong(obj); -#endif - if (*sec == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - goto overflow; - else - return -1; + *sec = _PyLong_AsTime_t(obj); + if (*sec == (time_t)-1 && PyErr_Occurred()) + return -1; + *numerator = 0; + return 0; + } +} + +int +_PyTime_ObjectToTime_t(PyObject *obj, time_t *sec) +{ + if (PyFloat_Check(obj)) { + double d, intpart, err; + + /*whent = _PyTime_DoubleToTimet(d);*/ + + d = PyFloat_AsDouble(obj); + (void)modf(d, &intpart); + + *sec = (time_t)intpart; + err = intpart - (double)*sec; + if (err <= -1.0 || err >= 1.0) { + error_time_t_overflow(); + return -1; } - *nsec = 0; return 0; } + else { + *sec = _PyLong_AsTime_t(obj); + if (*sec == (time_t)-1 && PyErr_Occurred()) + return -1; + return 0; + } +} -overflow: - PyErr_SetString(PyExc_OverflowError, - "timestamp out of range for platform time_t"); - return -1; +int +_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec) +{ + return _PyTime_ObjectToDenominator(obj, sec, nsec, 1e9); +} + +int +_PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec) +{ + return _PyTime_ObjectToDenominator(obj, sec, usec, 1e6); } void -- cgit v1.2.1 From 08a3385bd19cd7a0ac32758f3f24fbdd49ad4fda Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 13 Mar 2012 13:50:34 +0100 Subject: Issue #14180: Remove commented code --- Python/pytime.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'Python/pytime.c') diff --git a/Python/pytime.c b/Python/pytime.c index 79a1a33616..75d80e2576 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -137,8 +137,6 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec) if (PyFloat_Check(obj)) { double d, intpart, err; - /*whent = _PyTime_DoubleToTimet(d);*/ - d = PyFloat_AsDouble(obj); (void)modf(d, &intpart); -- cgit v1.2.1 From 75ff7e8c4aa9633a8c87788c24ab8335fa1dd698 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 13 Mar 2012 19:12:23 +0100 Subject: Issue #14180: Fix an invalid rounding when compiler optimization are enabled Use volatile keyword to disable localy unsafe float optimizations. --- Python/pytime.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Python/pytime.c') diff --git a/Python/pytime.c b/Python/pytime.c index 75d80e2576..e7dadc7605 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -102,7 +102,9 @@ _PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator, { assert(denominator <= LONG_MAX); if (PyFloat_Check(obj)) { - double d, intpart, floatpart, err; + double d, intpart, err; + /* volatile avoids unsafe optimization on float enabled by gcc -O3 */ + volatile double floatpart; d = PyFloat_AsDouble(obj); floatpart = modf(d, &intpart); -- cgit v1.2.1