changeset: 95272:f6b41566ca28 user: Victor Stinner date: Mon Mar 30 03:52:49 2015 +0200 files: Include/pytime.h Lib/test/test_time.py Modules/_testcapimodule.c Python/pytime.c description: Issue #22117: Add _PyTime_ROUND_CEILING rounding method for timestamps Add also more tests for ROUNd_FLOOR. diff -r fe9a578d5f38 -r f6b41566ca28 Include/pytime.h --- a/Include/pytime.h Sun Mar 29 21:54:27 2015 -0400 +++ b/Include/pytime.h Mon Mar 30 03:52:49 2015 +0200 @@ -32,7 +32,10 @@ _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 -r fe9a578d5f38 -r f6b41566ca28 Lib/test/test_time.py --- a/Lib/test/test_time.py Sun Mar 29 21:54:27 2015 -0400 +++ b/Lib/test/test_time.py Mon Mar 30 03:52:49 2015 +0200 @@ -28,13 +28,16 @@ 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 @@ (-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 @@ (-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 @@ (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 @@ (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 @@ 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 @@ 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 -r fe9a578d5f38 -r f6b41566ca28 Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Sun Mar 29 21:54:27 2015 -0400 +++ b/Modules/_testcapimodule.c Mon Mar 30 03:52:49 2015 +0200 @@ -2635,7 +2635,7 @@ 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 -r fe9a578d5f38 -r f6b41566ca28 Python/pytime.c --- a/Python/pytime.c Sun Mar 29 21:54:27 2015 -0400 +++ b/Python/pytime.c Mon Mar 30 03:52:49 2015 +0200 @@ -31,6 +31,8 @@ { if (round == _PyTime_ROUND_FLOOR) return 0; + if (round == _PyTime_ROUND_CEILING) + return 1; return ((round == _PyTime_ROUND_UP) ^ is_neg); }