[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