From bcdd777d3c01a6db3b4357922663624ef617e65a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 30 Mar 2015 03:52:49 +0200 Subject: [PATCH] Issue #22117: Add _PyTime_ROUND_CEILING rounding method for timestamps Add also more tests for ROUNd_FLOOR. --- Include/pytime.h | 5 ++- Lib/test/test_time.py | 65 ++++++++++++++++++++++++++++++++++++--- Modules/_testcapimodule.c | 2 +- Python/pytime.c | 2 ++ 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/Include/pytime.h b/Include/pytime.h index f14e1fc6fde..ff3e203e359 100644 --- a/Include/pytime.h +++ b/Include/pytime.h @@ -32,7 +32,10 @@ typedef enum { _PyTime_ROUND_UP, /* Round towards minus infinity (-inf). For example, used to read a clock. */ - _PyTime_ROUND_FLOOR + _PyTime_ROUND_FLOOR, + /* Round towards infinity (+inf). + For example, used for timeout to wait "at least" N seconds. */ + _PyTime_ROUND_CEILING } _PyTime_round_t; /* Convert a time_t to a PyLong. */ diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index bcbf41d0db8..472110c687a 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -28,13 +28,16 @@ class _PyTime(enum.IntEnum): ROUND_DOWN = 0 # Round away from zero ROUND_UP = 1 - # Round towards -Infinity + # Round towards minus infinity (-inf) ROUND_FLOOR = 2 + # Round towards infinity (+inf) + ROUND_CEILING = 3 ALL_ROUNDING_METHODS = ( _PyTime.ROUND_UP, _PyTime.ROUND_DOWN, - _PyTime.ROUND_FLOOR) + _PyTime.ROUND_FLOOR, + _PyTime.ROUND_CEILING) class TimeTestCase(unittest.TestCase): @@ -621,6 +624,13 @@ class TestPytime(unittest.TestCase): (-1.9, -1, _PyTime.ROUND_DOWN), (1.0, 1, _PyTime.ROUND_DOWN), (1.9, 1, _PyTime.ROUND_DOWN), + # Round towards minus infinity (-inf) + (0, 0, _PyTime.ROUND_FLOOR), + (-1, -1, _PyTime.ROUND_FLOOR), + (-1.0, -1, _PyTime.ROUND_FLOOR), + (-1.9, -2, _PyTime.ROUND_FLOOR), + (1.0, 1, _PyTime.ROUND_FLOOR), + (1.9, 1, _PyTime.ROUND_FLOOR), # Round away from zero (0, 0, _PyTime.ROUND_UP), (-1, -1, _PyTime.ROUND_UP), @@ -628,10 +638,17 @@ class TestPytime(unittest.TestCase): (-1.9, -2, _PyTime.ROUND_UP), (1.0, 1, _PyTime.ROUND_UP), (1.9, 2, _PyTime.ROUND_UP), + # Round towards infinity (+inf) + (0, 0, _PyTime.ROUND_CEILING), + (-1, -1, _PyTime.ROUND_CEILING), + (-1.0, -1, _PyTime.ROUND_CEILING), + (-1.9, -1, _PyTime.ROUND_CEILING), + (1.0, 1, _PyTime.ROUND_CEILING), + (1.9, 2, _PyTime.ROUND_CEILING), ): self.assertEqual(pytime_object_to_time_t(obj, rnd), time_t) - rnd = _PyTime.ROUND_DOWN + rnd = _PyTime.ROUND_FLOOR for invalid in self.invalid_values: self.assertRaises(OverflowError, pytime_object_to_time_t, invalid, rnd) @@ -654,6 +671,20 @@ class TestPytime(unittest.TestCase): (1.1234567899, (1, 123456789), _PyTime.ROUND_DOWN), (-1.1234567890, (-2, 876543211), _PyTime.ROUND_DOWN), (-1.1234567891, (-2, 876543211), _PyTime.ROUND_DOWN), + # Round towards minus infinity (-inf) + (0, (0, 0), _PyTime.ROUND_FLOOR), + (-1, (-1, 0), _PyTime.ROUND_FLOOR), + (-1.0, (-1, 0), _PyTime.ROUND_FLOOR), + (1e-9, (0, 1), _PyTime.ROUND_FLOOR), + (1e-10, (0, 0), _PyTime.ROUND_FLOOR), + (-1e-9, (-1, 999999999), _PyTime.ROUND_FLOOR), + (-1e-10, (-1, 999999999), _PyTime.ROUND_FLOOR), + (-1.2, (-2, 800000000), _PyTime.ROUND_FLOOR), + (0.9999999999, (0, 999999999), _PyTime.ROUND_FLOOR), + (1.1234567890, (1, 123456789), _PyTime.ROUND_FLOOR), + (1.1234567899, (1, 123456789), _PyTime.ROUND_FLOOR), + (-1.1234567890, (-2, 876543211), _PyTime.ROUND_FLOOR), + (-1.1234567891, (-2, 876543210), _PyTime.ROUND_FLOOR), # Round away from zero (0, (0, 0), _PyTime.ROUND_UP), (-1, (-1, 0), _PyTime.ROUND_UP), @@ -668,11 +699,25 @@ class TestPytime(unittest.TestCase): (1.1234567899, (1, 123456790), _PyTime.ROUND_UP), (-1.1234567890, (-2, 876543211), _PyTime.ROUND_UP), (-1.1234567891, (-2, 876543210), _PyTime.ROUND_UP), + # Round towards infinity (+inf) + (0, (0, 0), _PyTime.ROUND_CEILING), + (-1, (-1, 0), _PyTime.ROUND_CEILING), + (-1.0, (-1, 0), _PyTime.ROUND_CEILING), + (1e-9, (0, 1), _PyTime.ROUND_CEILING), + (1e-10, (0, 1), _PyTime.ROUND_CEILING), + (-1e-9, (-1, 999999999), _PyTime.ROUND_CEILING), + (-1e-10, (0, 0), _PyTime.ROUND_CEILING), + (-1.2, (-2, 800000000), _PyTime.ROUND_CEILING), + (0.9999999999, (1, 0), _PyTime.ROUND_CEILING), + (1.1234567890, (1, 123456790), _PyTime.ROUND_CEILING), + (1.1234567899, (1, 123456790), _PyTime.ROUND_CEILING), + (-1.1234567890, (-2, 876543211), _PyTime.ROUND_CEILING), + (-1.1234567891, (-2, 876543211), _PyTime.ROUND_CEILING), ): with self.subTest(obj=obj, round=rnd, timespec=timespec): self.assertEqual(pytime_object_to_timespec(obj, rnd), timespec) - rnd = _PyTime.ROUND_DOWN + rnd = _PyTime.ROUND_FLOOR for invalid in self.invalid_values: self.assertRaises(OverflowError, pytime_object_to_timespec, invalid, rnd) @@ -794,27 +839,34 @@ class TestPyTime_t(unittest.TestCase): UP = _PyTime.ROUND_UP DOWN = _PyTime.ROUND_DOWN FLOOR = _PyTime.ROUND_FLOOR + CEILING = _PyTime.ROUND_CEILING for obj, ts, rnd in ( # close to zero + ( 1e-10, 1, CEILING), ( 1e-10, 1, UP), ( 1e-10, 0, DOWN), ( 1e-10, 0, FLOOR), + (-1e-10, 0, CEILING), (-1e-10, 0, DOWN), (-1e-10, -1, UP), (-1e-10, -1, FLOOR), # test rounding of the last nanosecond + ( 1.1234567899, 1123456790, CEILING), ( 1.1234567899, 1123456790, UP), ( 1.1234567899, 1123456789, DOWN), ( 1.1234567899, 1123456789, FLOOR), + (-1.1234567899, -1123456789, CEILING), (-1.1234567899, -1123456789, DOWN), (-1.1234567899, -1123456790, UP), (-1.1234567899, -1123456790, FLOOR), # close to 1 second + ( 0.9999999999, 1000000000, CEILING), ( 0.9999999999, 1000000000, UP), ( 0.9999999999, 999999999, DOWN), ( 0.9999999999, 999999999, FLOOR), + (-0.9999999999, -999999999, CEILING), (-0.9999999999, -999999999, DOWN), (-0.9999999999, -1000000000, UP), (-0.9999999999, -1000000000, FLOOR), @@ -890,19 +942,24 @@ class TestPyTime_t(unittest.TestCase): UP = _PyTime.ROUND_UP DOWN = _PyTime.ROUND_DOWN FLOOR = _PyTime.ROUND_FLOOR + CEILING = _PyTime.ROUND_CEILING for ns, tv, rnd in ( # nanoseconds + (1, (0, 1), CEILING), (1, (0, 1), UP), (1, (0, 0), DOWN), (1, (0, 0), FLOOR), + (-1, (0, 0), CEILING), (-1, (0, 0), DOWN), (-1, (-1, 999999), UP), (-1, (-1, 999999), FLOOR), # seconds + nanoseconds + (1234567001, (1, 234568), CEILING), (1234567001, (1, 234568), UP), (1234567001, (1, 234567), DOWN), (1234567001, (1, 234567), FLOOR), + (-1234567001, (-2, 765433), CEILING), (-1234567001, (-2, 765433), DOWN), (-1234567001, (-2, 765432), UP), (-1234567001, (-2, 765432), FLOOR), diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 128ba094b2e..25f916beb9e 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2635,7 +2635,7 @@ static int check_time_rounding(int round) { if (round != _PyTime_ROUND_DOWN && round != _PyTime_ROUND_UP - && round != _PyTime_ROUND_FLOOR) { + && round != _PyTime_ROUND_FLOOR && round != _PyTime_ROUND_CEILING) { PyErr_SetString(PyExc_ValueError, "invalid rounding"); return -1; } diff --git a/Python/pytime.c b/Python/pytime.c index 0d28911c378..ca4386aa089 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -31,6 +31,8 @@ _PyTime_RoundTowardsPosInf(int is_neg, _PyTime_round_t round) { if (round == _PyTime_ROUND_FLOOR) return 0; + if (round == _PyTime_ROUND_CEILING) + return 1; return ((round == _PyTime_ROUND_UP) ^ is_neg); }