[Python-checkins] cpython: Issue #22117, issue #23485: Fix _PyTime_AsMilliseconds() and
victor.stinner
python-checkins at python.org
Wed Apr 1 17:51:07 CEST 2015
https://hg.python.org/cpython/rev/65ac8e587bb0
changeset: 95351:65ac8e587bb0
user: Victor Stinner <victor.stinner at gmail.com>
date: Wed Apr 01 17:47:07 2015 +0200
summary:
Issue #22117, issue #23485: Fix _PyTime_AsMilliseconds() and
_PyTime_AsMicroseconds() rounding.
Add also unit tests.
files:
Lib/test/test_time.py | 76 +++++++++++++++++++++++++-
Modules/_testcapimodule.c | 38 +++++++++++++
Python/pytime.c | 26 ++++----
3 files changed, 123 insertions(+), 17 deletions(-)
diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -21,6 +21,8 @@
TIME_MAXYEAR = (1 << 8 * SIZEOF_INT - 1) - 1
TIME_MINYEAR = -TIME_MAXYEAR - 1
+US_TO_NS = 10 ** 3
+MS_TO_NS = 10 ** 6
SEC_TO_NS = 10 ** 9
class _PyTime(enum.IntEnum):
@@ -867,10 +869,6 @@
# seconds
(2 * SEC_TO_NS, (2, 0)),
(-3 * SEC_TO_NS, (-3, 0)),
-
- # seconds + nanoseconds
- (1234567000, (1, 234567)),
- (-1234567000, (-2, 765433)),
):
with self.subTest(nanoseconds=ns, timeval=tv, round=rnd):
self.assertEqual(PyTime_AsTimeval(ns, rnd), tv)
@@ -914,6 +912,76 @@
with self.subTest(nanoseconds=ns, timespec=ts):
self.assertEqual(PyTime_AsTimespec(ns), ts)
+ def test_milliseconds(self):
+ from _testcapi import PyTime_AsMilliseconds
+ for rnd in ALL_ROUNDING_METHODS:
+ for ns, tv in (
+ # milliseconds
+ (1 * MS_TO_NS, 1),
+ (-2 * MS_TO_NS, -2),
+
+ # seconds
+ (2 * SEC_TO_NS, 2000),
+ (-3 * SEC_TO_NS, -3000),
+ ):
+ with self.subTest(nanoseconds=ns, timeval=tv, round=rnd):
+ self.assertEqual(PyTime_AsMilliseconds(ns, rnd), tv)
+
+ FLOOR = _PyTime.ROUND_FLOOR
+ CEILING = _PyTime.ROUND_CEILING
+ for ns, ms, rnd in (
+ # nanoseconds
+ (1, 0, FLOOR),
+ (1, 1, CEILING),
+ (-1, 0, FLOOR),
+ (-1, -1, CEILING),
+
+ # seconds + nanoseconds
+ (1234 * MS_TO_NS + 1, 1234, FLOOR),
+ (1234 * MS_TO_NS + 1, 1235, CEILING),
+ (-1234 * MS_TO_NS - 1, -1234, FLOOR),
+ (-1234 * MS_TO_NS - 1, -1235, CEILING),
+ ):
+ with self.subTest(nanoseconds=ns, milliseconds=ms, round=rnd):
+ self.assertEqual(PyTime_AsMilliseconds(ns, rnd), ms)
+
+ def test_microseconds(self):
+ from _testcapi import PyTime_AsMicroseconds
+ for rnd in ALL_ROUNDING_METHODS:
+ for ns, tv in (
+ # microseconds
+ (1 * US_TO_NS, 1),
+ (-2 * US_TO_NS, -2),
+
+ # milliseconds
+ (1 * MS_TO_NS, 1000),
+ (-2 * MS_TO_NS, -2000),
+
+ # seconds
+ (2 * SEC_TO_NS, 2000000),
+ (-3 * SEC_TO_NS, -3000000),
+ ):
+ with self.subTest(nanoseconds=ns, timeval=tv, round=rnd):
+ self.assertEqual(PyTime_AsMicroseconds(ns, rnd), tv)
+
+ FLOOR = _PyTime.ROUND_FLOOR
+ CEILING = _PyTime.ROUND_CEILING
+ for ns, ms, rnd in (
+ # nanoseconds
+ (1, 0, FLOOR),
+ (1, 1, CEILING),
+ (-1, 0, FLOOR),
+ (-1, -1, CEILING),
+
+ # seconds + nanoseconds
+ (1234 * US_TO_NS + 1, 1234, FLOOR),
+ (1234 * US_TO_NS + 1, 1235, CEILING),
+ (-1234 * US_TO_NS - 1, -1234, FLOOR),
+ (-1234 * US_TO_NS - 1, -1235, CEILING),
+ ):
+ with self.subTest(nanoseconds=ns, milliseconds=ms, round=rnd):
+ self.assertEqual(PyTime_AsMicroseconds(ns, rnd), ms)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -3452,6 +3452,42 @@
}
#endif
+static PyObject *
+test_PyTime_AsMilliseconds(PyObject *self, PyObject *args)
+{
+ PY_LONG_LONG ns;
+ int round;
+ _PyTime_t t, ms;
+
+ if (!PyArg_ParseTuple(args, "Li", &ns, &round))
+ return NULL;
+ if (check_time_rounding(round) < 0)
+ return NULL;
+ t = _PyTime_FromNanoseconds(ns);
+ ms = _PyTime_AsMilliseconds(t, round);
+ /* This conversion rely on the fact that _PyTime_t is a number of
+ nanoseconds */
+ return _PyTime_AsNanosecondsObject(ms);
+}
+
+static PyObject *
+test_PyTime_AsMicroseconds(PyObject *self, PyObject *args)
+{
+ PY_LONG_LONG ns;
+ int round;
+ _PyTime_t t, ms;
+
+ if (!PyArg_ParseTuple(args, "Li", &ns, &round))
+ return NULL;
+ if (check_time_rounding(round) < 0)
+ return NULL;
+ t = _PyTime_FromNanoseconds(ns);
+ ms = _PyTime_AsMicroseconds(t, round);
+ /* This conversion rely on the fact that _PyTime_t is a number of
+ nanoseconds */
+ return _PyTime_AsNanosecondsObject(ms);
+}
+
static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS},
@@ -3621,6 +3657,8 @@
#ifdef HAVE_CLOCK_GETTIME
{"PyTime_AsTimespec", test_PyTime_AsTimespec, METH_VARARGS},
#endif
+ {"PyTime_AsMilliseconds", test_PyTime_AsMilliseconds, METH_VARARGS},
+ {"PyTime_AsMicroseconds", test_PyTime_AsMicroseconds, METH_VARARGS},
{NULL, NULL} /* sentinel */
};
diff --git a/Python/pytime.c b/Python/pytime.c
--- a/Python/pytime.c
+++ b/Python/pytime.c
@@ -19,6 +19,10 @@
#define MS_TO_NS (MS_TO_US * US_TO_NS)
#define SEC_TO_NS (SEC_TO_MS * MS_TO_NS)
+/* Conversion from nanoseconds */
+#define NS_TO_MS (1000 * 1000)
+#define NS_TO_US (1000)
+
static void
error_time_t_overflow(void)
{
@@ -288,33 +292,29 @@
}
static _PyTime_t
-_PyTime_Multiply(_PyTime_t t, unsigned int multiply, _PyTime_round_t round)
+_PyTime_Divide(_PyTime_t t, _PyTime_t k, _PyTime_round_t round)
{
- _PyTime_t k;
- if (multiply < SEC_TO_NS) {
- k = SEC_TO_NS / multiply;
- if (round == _PyTime_ROUND_CEILING)
+ assert(k > 1);
+ if (round == _PyTime_ROUND_CEILING) {
+ if (t >= 0)
return (t + k - 1) / k;
else
- return t / k;
+ return (t - (k - 1)) / k;
}
- else {
- k = multiply / SEC_TO_NS;
- return t * k;
- }
+ else
+ return t / k;
}
_PyTime_t
_PyTime_AsMilliseconds(_PyTime_t t, _PyTime_round_t round)
{
- return _PyTime_Multiply(t, 1000, round);
+ return _PyTime_Divide(t, NS_TO_MS, round);
}
-/* FIXME: write unit tests */
_PyTime_t
_PyTime_AsMicroseconds(_PyTime_t t, _PyTime_round_t round)
{
- return _PyTime_Multiply(t, 1000 * 1000, round);
+ return _PyTime_Divide(t, NS_TO_US, round);
}
static int
--
Repository URL: https://hg.python.org/cpython
More information about the Python-checkins
mailing list