diff -r 67d9595a833c -r bd88a2a791c8 Doc/library/datetime.rst --- a/Doc/library/datetime.rst Fri Mar 02 22:54:03 2012 +0100 +++ b/Doc/library/datetime.rst Sat Mar 03 01:02:52 2012 +0100 @@ -395,12 +395,17 @@ Other constructors, all class methods: .. classmethod:: date.fromtimestamp(timestamp) Return the local date corresponding to the POSIX timestamp, such as is returned - by :func:`time.time`. This may raise :exc:`ValueError`, if the timestamp is out + by :func:`time.time`. This may raise :exc:`OverflowError`, if the timestamp is out of the range of values supported by the platform C :c:func:`localtime` function. It's common for this to be restricted to years from 1970 through 2038. Note that on non-POSIX systems that include leap seconds in their notion of a timestamp, leap seconds are ignored by :meth:`fromtimestamp`. + .. versionchanged:: 3.3 + Raise :exc:`OverflowError` instead of :exc:`ValueError` if the timestamp + is out of the range of values supported by the platform C + :c:func:`localtime` function. + .. classmethod:: date.fromordinal(ordinal) @@ -712,6 +717,11 @@ Other constructors, all class methods: and then it's possible to have two timestamps differing by a second that yield identical :class:`.datetime` objects. See also :meth:`utcfromtimestamp`. + .. versionchanged:: 3.3 + Raise :exc:`OverflowError` instead of :exc:`ValueError` if the timestamp + is out of the range of values supported by the platform C + :c:func:`localtime` or :c:func:`gmtime` functions + .. classmethod:: datetime.utcfromtimestamp(timestamp) @@ -737,6 +747,11 @@ Other constructors, all class methods: timestamp = (dt - datetime(1970, 1, 1, tzinfo=timezone.utc)) / timedelta(seconds=1) + .. versionchanged:: 3.3 + Raise :exc:`OverflowError` instead of :exc:`ValueError` if the timestamp + is out of the range of values supported by the platform C + :c:func:`gmtime` function. + .. classmethod:: datetime.fromordinal(ordinal) diff -r 67d9595a833c -r bd88a2a791c8 Include/pytime.h --- a/Include/pytime.h Fri Mar 02 22:54:03 2012 +0100 +++ b/Include/pytime.h Sat Mar 03 01:02:52 2012 +0100 @@ -39,6 +39,19 @@ do { \ (tv_end.tv_usec - tv_start.tv_usec) * 0.000001) #ifndef Py_LIMITED_API +/* Convert a number of seconds, int or float, to time_t. */ +PyAPI_FUNC(int) _PyTime_ObjectToTime_t( + PyObject *obj, + time_t *sec); + +/* Convert a number of seconds, int or float, to a timeval structure. + usec is always in the range [0; 999999]. For example, -1.2 is converted + to (-2, 800000). */ +PyAPI_FUNC(int) _PyTime_ObjectToTimeval( + PyObject *obj, + time_t *sec, + long *usec); + /* Convert a number of seconds, int or float, to a timespec structure. nsec is always in the range [0; 999999999]. For example, -1.2 is converted to (-2, 800000000). */ diff -r 67d9595a833c -r bd88a2a791c8 Include/timefuncs.h --- a/Include/timefuncs.h Fri Mar 02 22:54:03 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* timefuncs.h - */ - -/* Utility function related to timemodule.c. */ - -#ifndef TIMEFUNCS_H -#define TIMEFUNCS_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Cast double x to time_t, but raise ValueError if x is too large - * to fit in a time_t. ValueError is set on return iff the return - * value is (time_t)-1 and PyErr_Occurred(). - */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(time_t) _PyTime_DoubleToTimet(double x); -#endif - - -#ifdef __cplusplus -} -#endif -#endif /* TIMEFUNCS_H */ diff -r 67d9595a833c -r bd88a2a791c8 Lib/datetime.py --- a/Lib/datetime.py Fri Mar 02 22:54:03 2012 +0100 +++ b/Lib/datetime.py Sat Mar 03 01:02:52 2012 +0100 @@ -1360,7 +1360,7 @@ class datetime(date): converter = _time.localtime if tz is None else _time.gmtime t, frac = divmod(t, 1.0) - us = round(frac * 1e6) + us = int(frac * 1e6) # If timestamp is less than one microsecond smaller than a # full second, us can be rounded up to 1000000. In this case, @@ -1380,7 +1380,7 @@ class datetime(date): def utcfromtimestamp(cls, t): "Construct a UTC datetime from a POSIX timestamp (like time.time())." t, frac = divmod(t, 1.0) - us = round(frac * 1e6) + us = int(frac * 1e6) # If timestamp is less than one microsecond smaller than a # full second, us can be rounded up to 1000000. In this case, diff -r 67d9595a833c -r bd88a2a791c8 Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py Fri Mar 02 22:54:03 2012 +0100 +++ b/Lib/test/datetimetester.py Sat Mar 03 01:02:52 2012 +0100 @@ -977,7 +977,7 @@ class TestDate(HarmlessMixedComparison, # exempt such platforms (provided they return reasonable # results!). for insane in -1e200, 1e200: - self.assertRaises(ValueError, self.theclass.fromtimestamp, + self.assertRaises(OverflowError, self.theclass.fromtimestamp, insane) def test_today(self): @@ -1736,12 +1736,16 @@ class TestDateTime(TestDate): self.verify_field_equality(expected, got) def test_microsecond_rounding(self): - # Test whether fromtimestamp "rounds up" floats that are less + # Test whether fromtimestamp "rounds down" floats that are less # than 1/2 microsecond smaller than an integer. for fts in [self.theclass.fromtimestamp, self.theclass.utcfromtimestamp]: - self.assertEqual(fts(0.9999999), fts(1)) - self.assertEqual(fts(0.99999949).microsecond, 999999) + t = fts(0.9999999) + self.assertEqual(t.second, 0) + self.assertEqual(t.microsecond, 999999) + t = fts(0.99999949) + self.assertEqual(t.second, 0) + self.assertEqual(t.microsecond, 999999) def test_insane_fromtimestamp(self): # It's possible that some platform maps time_t to double, @@ -1749,7 +1753,7 @@ class TestDateTime(TestDate): # exempt such platforms (provided they return reasonable # results!). for insane in -1e200, 1e200: - self.assertRaises(ValueError, self.theclass.fromtimestamp, + self.assertRaises(OverflowError, self.theclass.fromtimestamp, insane) def test_insane_utcfromtimestamp(self): @@ -1758,7 +1762,7 @@ class TestDateTime(TestDate): # exempt such platforms (provided they return reasonable # results!). for insane in -1e200, 1e200: - self.assertRaises(ValueError, self.theclass.utcfromtimestamp, + self.assertRaises(OverflowError, self.theclass.utcfromtimestamp, insane) @unittest.skipIf(sys.platform == "win32", "Windows doesn't accept negative timestamps") def test_negative_float_fromtimestamp(self): diff -r 67d9595a833c -r bd88a2a791c8 Lib/test/test_time.py --- a/Lib/test/test_time.py Fri Mar 02 22:54:03 2012 +0100 +++ b/Lib/test/test_time.py Sat Mar 03 01:02:52 2012 +0100 @@ -281,7 +281,7 @@ class TimeTestCase(unittest.TestCase): # results!). for func in time.ctime, time.gmtime, time.localtime: for unreasonable in -1e200, 1e200: - self.assertRaises(ValueError, func, unreasonable) + self.assertRaises(OverflowError, func, unreasonable) def test_ctime_without_arg(self): # Not sure how to check the values, since the clock could tick @@ -498,19 +498,63 @@ class TestStrftime4dyear(_TestStrftimeYe class TestPytime(unittest.TestCase): + def setUp(self): + self.invalid_values = ( + -(2 ** 100), 2 ** 100, + -(2.0 ** 100.0), 2.0 ** 100.0, + ) + + def test_time_t(self): + from _testcapi import pytime_object_to_time_t + for obj, time_t in ( + (0, 0), + (-1, -1), + (-1.0, -1), + (-1.9, -1), + (1.0, 1), + (1.9, 1), + ): + self.assertEqual(pytime_object_to_time_t(obj), time_t) + + for invalid in self.invalid_values: + self.assertRaises(OverflowError, pytime_object_to_time_t, invalid) + + def test_timeval(self): + from _testcapi import pytime_object_to_timeval + for obj, timeval in ( + (0, (0, 0)), + (-1, (-1, 0)), + (-1.0, (-1, 0)), + (1e-6, (0, 1)), + (-1e-6, (-1, 999999)), + (-1.2, (-2, 800000)), + (1.1234560, (1, 123456)), + (1.1234569, (1, 123456)), + (-1.1234560, (-2, 876544)), + (-1.1234561, (-2, 876543)), + ): + self.assertEqual(pytime_object_to_timeval(obj), timeval) + + for invalid in self.invalid_values: + self.assertRaises(OverflowError, pytime_object_to_timeval, invalid) + def test_timespec(self): from _testcapi import pytime_object_to_timespec for obj, timespec in ( (0, (0, 0)), (-1, (-1, 0)), (-1.0, (-1, 0)), + (1e-9, (0, 1)), (-1e-9, (-1, 999999999)), (-1.2, (-2, 800000000)), - (1.123456789, (1, 123456789)), + (1.1234567890, (1, 123456789)), + (1.1234567899, (1, 123456789)), + (-1.1234567890, (-2, 876543211)), + (-1.1234567891, (-2, 876543210)), ): self.assertEqual(pytime_object_to_timespec(obj), timespec) - for invalid in (-(2 ** 100), -(2.0 ** 100.0), 2 ** 100, 2.0 ** 100.0): + for invalid in self.invalid_values: self.assertRaises(OverflowError, pytime_object_to_timespec, invalid) diff -r 67d9595a833c -r bd88a2a791c8 Misc/NEWS --- a/Misc/NEWS Fri Mar 02 22:54:03 2012 +0100 +++ b/Misc/NEWS Sat Mar 03 01:02:52 2012 +0100 @@ -511,6 +511,15 @@ Core and Builtins Library ------- +- 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. + - Issue #14159: Fix the len() of weak containers (WeakSet, WeakKeyDictionary, WeakValueDictionary) to return a better approximation when some objects are dead or dying. Moreover, the implementation is now O(1) rather than diff -r 67d9595a833c -r bd88a2a791c8 Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c Fri Mar 02 22:54:03 2012 +0100 +++ b/Modules/_datetimemodule.c Sat Mar 03 01:02:52 2012 +0100 @@ -7,8 +7,6 @@ #include -#include "_time.h" - /* Differentiate between building the core module and building extension * modules. */ @@ -2441,15 +2439,15 @@ date_new(PyTypeObject *type, PyObject *a /* Return new date from localtime(t). */ static PyObject * -date_local_from_time_t(PyObject *cls, double ts) +date_local_from_object(PyObject *cls, PyObject *obj) { struct tm *tm; time_t t; PyObject *result = NULL; - t = _PyTime_DoubleToTimet(ts); - if (t == (time_t)-1 && PyErr_Occurred()) + if (_PyTime_ObjectToTime_t(obj, &t) == -1) return NULL; + tm = localtime(&t); if (tm) result = PyObject_CallFunction(cls, "iii", @@ -2494,11 +2492,11 @@ date_today(PyObject *cls, PyObject *dumm static PyObject * date_fromtimestamp(PyObject *cls, PyObject *args) { - double timestamp; + PyObject *timestamp; PyObject *result = NULL; - if (PyArg_ParseTuple(args, "d:fromtimestamp", ×tamp)) - result = date_local_from_time_t(cls, timestamp); + if (PyArg_ParseTuple(args, "O:fromtimestamp", ×tamp)) + result = date_local_from_object(cls, timestamp); return result; } @@ -4096,31 +4094,14 @@ datetime_from_timet_and_us(PyObject *cls * to get that much precision (e.g., C time() isn't good enough). */ static PyObject * -datetime_from_timestamp(PyObject *cls, TM_FUNC f, double timestamp, +datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp, PyObject *tzinfo) { time_t timet; - double fraction; - int us; - - timet = _PyTime_DoubleToTimet(timestamp); - if (timet == (time_t)-1 && PyErr_Occurred()) + long us; + + if (_PyTime_ObjectToTimeval(timestamp, &timet, &us) == -1) return NULL; - fraction = timestamp - (double)timet; - us = (int)round_to_long(fraction * 1e6); - if (us < 0) { - /* Truncation towards zero is not what we wanted - for negative numbers (Python's mod semantics) */ - timet -= 1; - us += 1000000; - } - /* If timestamp is less than one microsecond smaller than a - * full second, round up. Otherwise, ValueErrors are raised - * for some floats. */ - if (us == 1000000) { - timet += 1; - us = 0; - } return datetime_from_timet_and_us(cls, f, timet, us, tzinfo); } @@ -4181,11 +4162,11 @@ static PyObject * datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) { PyObject *self; - double timestamp; + PyObject *timestamp; PyObject *tzinfo = Py_None; static char *keywords[] = {"timestamp", "tz", NULL}; - if (! PyArg_ParseTupleAndKeywords(args, kw, "d|O:fromtimestamp", + if (! PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp", keywords, ×tamp, &tzinfo)) return NULL; if (check_tzinfo_subclass(tzinfo) < 0) @@ -4210,10 +4191,10 @@ datetime_fromtimestamp(PyObject *cls, Py static PyObject * datetime_utcfromtimestamp(PyObject *cls, PyObject *args) { - double timestamp; + PyObject *timestamp; PyObject *result = NULL; - if (PyArg_ParseTuple(args, "d:utcfromtimestamp", ×tamp)) + if (PyArg_ParseTuple(args, "O:utcfromtimestamp", ×tamp)) result = datetime_from_timestamp(cls, gmtime, timestamp, Py_None); return result; diff -r 67d9595a833c -r bd88a2a791c8 Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Fri Mar 02 22:54:03 2012 +0100 +++ b/Modules/_testcapimodule.c Sat Mar 03 01:02:52 2012 +0100 @@ -2323,6 +2323,42 @@ run_in_subinterp(PyObject *self, PyObjec return PyLong_FromLong(r); } +static PyObject* +_PyLong_FromTime_t(time_t value) +{ +#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG + return PyLong_FromLongLong(value); +#else + assert(sizeof(time_t) <= sizeof(long)); + return PyLong_FromLong(value); +#endif +} + +static PyObject * +test_pytime_object_to_time_t(PyObject *self, PyObject *args) +{ + PyObject *obj; + time_t sec; + if (!PyArg_ParseTuple(args, "O:pytime_object_to_time_t", &obj)) + return NULL; + if (_PyTime_ObjectToTime_t(obj, &sec) == -1) + return NULL; + return _PyLong_FromTime_t(sec); +} + +static PyObject * +test_pytime_object_to_timeval(PyObject *self, PyObject *args) +{ + PyObject *obj; + time_t sec; + long usec; + if (!PyArg_ParseTuple(args, "O:pytime_object_to_timeval", &obj)) + return NULL; + if (_PyTime_ObjectToTimeval(obj, &sec, &usec) == -1) + return NULL; + return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), usec); +} + static PyObject * test_pytime_object_to_timespec(PyObject *self, PyObject *args) { @@ -2333,12 +2369,7 @@ test_pytime_object_to_timespec(PyObject return NULL; if (_PyTime_ObjectToTimespec(obj, &sec, &nsec) == -1) return NULL; -#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG - return Py_BuildValue("Ll", (PY_LONG_LONG)sec, nsec); -#else - assert(sizeof(time_t) <= sizeof(long)); - return Py_BuildValue("ll", (long)sec, nsec); -#endif + return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), nsec); } @@ -2430,6 +2461,8 @@ static PyMethodDef TestMethods[] = { METH_NOARGS}, {"crash_no_current_thread", (PyCFunction)crash_no_current_thread, METH_NOARGS}, {"run_in_subinterp", run_in_subinterp, METH_VARARGS}, + {"pytime_object_to_time_t", test_pytime_object_to_time_t, METH_VARARGS}, + {"pytime_object_to_timeval", test_pytime_object_to_timeval, METH_VARARGS}, {"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff -r 67d9595a833c -r bd88a2a791c8 Modules/_time.c --- a/Modules/_time.c Fri Mar 02 22:54:03 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -#include "Python.h" -#include "_time.h" - -/* Exposed in timefuncs.h. */ -time_t -_PyTime_DoubleToTimet(double x) -{ - time_t result; - double diff; - - result = (time_t)x; - /* How much info did we lose? time_t may be an integral or - * floating type, and we don't know which. If it's integral, - * we don't know whether C truncates, rounds, returns the floor, - * etc. If we lost a second or more, the C rounding is - * unreasonable, or the input just doesn't fit in a time_t; - * call it an error regardless. Note that the original cast to - * time_t can cause a C error too, but nothing we can do to - * work around that. - */ - diff = x - (double)result; - if (diff <= -1.0 || diff >= 1.0) { - PyErr_SetString(PyExc_ValueError, - "timestamp out of range for platform time_t"); - result = (time_t)-1; - } - return result; -} diff -r 67d9595a833c -r bd88a2a791c8 Modules/_time.h --- a/Modules/_time.h Fri Mar 02 22:54:03 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -/* XXX: It is probably best to move timefuncs.h content in here, and - remove it but user code may rely on it. */ -#include "timefuncs.h" diff -r 67d9595a833c -r bd88a2a791c8 Modules/posixmodule.c --- a/Modules/posixmodule.c Fri Mar 02 22:54:03 2012 +0100 +++ b/Modules/posixmodule.c Sat Mar 03 01:02:52 2012 +0100 @@ -3541,28 +3541,9 @@ posix_uname(PyObject *self, PyObject *no static int -extract_time(PyObject *t, time_t* sec, long* nsec) -{ - time_t intval; - if (PyFloat_Check(t)) { - double d = PyFloat_AsDouble(t); - double mod; - *sec = (time_t)d; - mod = fmod(d, 1.0); - mod *= 1e9; - *nsec = (long)mod; - return 0; - } -#if SIZEOF_TIME_T > SIZEOF_LONG - intval = PyLong_AsUnsignedLongLongMask(t); -#else - intval = PyLong_AsLong(t); -#endif - if (intval == -1 && PyErr_Occurred()) - return -1; - *sec = intval; - *nsec = 0; - return 0; +extract_time(PyObject *obj, time_t* sec, long* nsec) +{ + return _PyTime_ObjectToTimespec(obj, sec, nsec); } PyDoc_STRVAR(posix_utime__doc__, diff -r 67d9595a833c -r bd88a2a791c8 Modules/selectmodule.c --- a/Modules/selectmodule.c Fri Mar 02 22:54:03 2012 +0100 +++ b/Modules/selectmodule.c Sat Mar 03 01:02:52 2012 +0100 @@ -206,9 +206,7 @@ select_select(PyObject *self, PyObject * PyObject *ret = NULL; PyObject *tout = Py_None; fd_set ifdset, ofdset, efdset; - double timeout; struct timeval tv, *tvp; - long seconds; int imax, omax, emax, max; int n; @@ -225,23 +223,12 @@ select_select(PyObject *self, PyObject * return NULL; } else { - timeout = PyFloat_AsDouble(tout); - if (timeout == -1 && PyErr_Occurred()) + if (_PyTime_ObjectToTimeval(tout, &tv.tv_sec, &tv.tv_usec) == -1) return NULL; - if (timeout > (double)LONG_MAX) { - PyErr_SetString(PyExc_OverflowError, - "timeout period too long"); + if (tv.tv_sec < 0) { + PyErr_SetString(PyExc_ValueError, "timeout must be non-negative"); return NULL; } - if (timeout < 0) { - PyErr_SetString(PyExc_ValueError, - "timeout must be non-negative"); - return NULL; - } - seconds = (long)timeout; - timeout = timeout - (double)seconds; - tv.tv_sec = seconds; - tv.tv_usec = (long)(timeout * 1E6); tvp = &tv; } @@ -1870,27 +1857,15 @@ kqueue_queue_control(kqueue_queue_Object ptimeoutspec = NULL; } else if (PyNumber_Check(otimeout)) { - double timeout; - long seconds; + if (_PyTime_ObjectToTimespec(otimeout, + &timeout.tv_sec, &timeout.tv_nsec) == -1) + return NULL; - timeout = PyFloat_AsDouble(otimeout); - if (timeout == -1 && PyErr_Occurred()) - return NULL; - if (timeout > (double)LONG_MAX) { - PyErr_SetString(PyExc_OverflowError, - "timeout period too long"); - return NULL; - } - if (timeout < 0) { + if (timeout.tv_sec < 0) { PyErr_SetString(PyExc_ValueError, "timeout must be positive or None"); return NULL; } - - seconds = (long)timeout; - timeout = timeout - (double)seconds; - timeoutspec.tv_sec = seconds; - timeoutspec.tv_nsec = (long)(timeout * 1E9); ptimeoutspec = &timeoutspec; } else { diff -r 67d9595a833c -r bd88a2a791c8 Modules/timemodule.c --- a/Modules/timemodule.c Fri Mar 02 22:54:03 2012 +0100 +++ b/Modules/timemodule.c Sat Mar 03 01:02:52 2012 +0100 @@ -1,7 +1,6 @@ /* Time module */ #include "Python.h" -#include "_time.h" #include @@ -284,11 +283,7 @@ parse_time_t_args(PyObject *args, char * whent = time(NULL); } else { - double d = PyFloat_AsDouble(ot); - if (PyErr_Occurred()) - return 0; - whent = _PyTime_DoubleToTimet(d); - if (whent == (time_t)-1 && PyErr_Occurred()) + if (_PyTime_ObjectToTime_t(ot, &whent) == -1) return 0; } *pwhen = whent; diff -r 67d9595a833c -r bd88a2a791c8 Python/pytime.c --- a/Python/pytime.c Fri Mar 02 22:54:03 2012 +0100 +++ b/Python/pytime.c Sat Mar 03 01:02:52 2012 +0100 @@ -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, *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; - } - *nsec = 0; + *sec = _PyLong_AsTime_t(obj); + if (*sec == (time_t)-1 && PyErr_Occurred()) + return -1; + *numerator = 0; return 0; } +} -overflow: - PyErr_SetString(PyExc_OverflowError, - "timestamp out of range for platform time_t"); - return -1; +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; + } + return 0; + } + else { + *sec = _PyLong_AsTime_t(obj); + if (*sec == (time_t)-1 && PyErr_Occurred()) + return -1; + return 0; + } +} + +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 diff -r 67d9595a833c -r bd88a2a791c8 setup.py --- a/setup.py Fri Mar 02 22:54:03 2012 +0100 +++ b/setup.py Sat Mar 03 01:02:52 2012 +0100 @@ -512,9 +512,9 @@ class PyBuildExt(build_ext): time_libs.append(lib) # time operations and variables - exts.append( Extension('time', ['timemodule.c', '_time.c'], + exts.append( Extension('time', ['timemodule.c'], libraries=time_libs) ) - exts.append( Extension('_datetime', ['_datetimemodule.c', '_time.c']) ) + exts.append( Extension('_datetime', ['_datetimemodule.c']) ) # random number generator implemented in C exts.append( Extension("_random", ["_randommodule.c"]) ) # bisect exporting patch: