Kaydet (Commit) bcdd777d authored tarafından Victor Stinner's avatar Victor Stinner

Issue #22117: Add _PyTime_ROUND_CEILING rounding method for timestamps

Add also more tests for ROUNd_FLOOR.
üst c4bb599b
...@@ -32,7 +32,10 @@ typedef enum { ...@@ -32,7 +32,10 @@ typedef enum {
_PyTime_ROUND_UP, _PyTime_ROUND_UP,
/* Round towards minus infinity (-inf). /* Round towards minus infinity (-inf).
For example, used to read a clock. */ 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; } _PyTime_round_t;
/* Convert a time_t to a PyLong. */ /* Convert a time_t to a PyLong. */
......
...@@ -28,13 +28,16 @@ class _PyTime(enum.IntEnum): ...@@ -28,13 +28,16 @@ class _PyTime(enum.IntEnum):
ROUND_DOWN = 0 ROUND_DOWN = 0
# Round away from zero # Round away from zero
ROUND_UP = 1 ROUND_UP = 1
# Round towards -Infinity # Round towards minus infinity (-inf)
ROUND_FLOOR = 2 ROUND_FLOOR = 2
# Round towards infinity (+inf)
ROUND_CEILING = 3
ALL_ROUNDING_METHODS = ( ALL_ROUNDING_METHODS = (
_PyTime.ROUND_UP, _PyTime.ROUND_UP,
_PyTime.ROUND_DOWN, _PyTime.ROUND_DOWN,
_PyTime.ROUND_FLOOR) _PyTime.ROUND_FLOOR,
_PyTime.ROUND_CEILING)
class TimeTestCase(unittest.TestCase): class TimeTestCase(unittest.TestCase):
...@@ -621,6 +624,13 @@ class TestPytime(unittest.TestCase): ...@@ -621,6 +624,13 @@ class TestPytime(unittest.TestCase):
(-1.9, -1, _PyTime.ROUND_DOWN), (-1.9, -1, _PyTime.ROUND_DOWN),
(1.0, 1, _PyTime.ROUND_DOWN), (1.0, 1, _PyTime.ROUND_DOWN),
(1.9, 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 # Round away from zero
(0, 0, _PyTime.ROUND_UP), (0, 0, _PyTime.ROUND_UP),
(-1, -1, _PyTime.ROUND_UP), (-1, -1, _PyTime.ROUND_UP),
...@@ -628,10 +638,17 @@ class TestPytime(unittest.TestCase): ...@@ -628,10 +638,17 @@ class TestPytime(unittest.TestCase):
(-1.9, -2, _PyTime.ROUND_UP), (-1.9, -2, _PyTime.ROUND_UP),
(1.0, 1, _PyTime.ROUND_UP), (1.0, 1, _PyTime.ROUND_UP),
(1.9, 2, _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) 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: for invalid in self.invalid_values:
self.assertRaises(OverflowError, self.assertRaises(OverflowError,
pytime_object_to_time_t, invalid, rnd) pytime_object_to_time_t, invalid, rnd)
...@@ -654,6 +671,20 @@ class TestPytime(unittest.TestCase): ...@@ -654,6 +671,20 @@ class TestPytime(unittest.TestCase):
(1.1234567899, (1, 123456789), _PyTime.ROUND_DOWN), (1.1234567899, (1, 123456789), _PyTime.ROUND_DOWN),
(-1.1234567890, (-2, 876543211), _PyTime.ROUND_DOWN), (-1.1234567890, (-2, 876543211), _PyTime.ROUND_DOWN),
(-1.1234567891, (-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 # Round away from zero
(0, (0, 0), _PyTime.ROUND_UP), (0, (0, 0), _PyTime.ROUND_UP),
(-1, (-1, 0), _PyTime.ROUND_UP), (-1, (-1, 0), _PyTime.ROUND_UP),
...@@ -668,11 +699,25 @@ class TestPytime(unittest.TestCase): ...@@ -668,11 +699,25 @@ class TestPytime(unittest.TestCase):
(1.1234567899, (1, 123456790), _PyTime.ROUND_UP), (1.1234567899, (1, 123456790), _PyTime.ROUND_UP),
(-1.1234567890, (-2, 876543211), _PyTime.ROUND_UP), (-1.1234567890, (-2, 876543211), _PyTime.ROUND_UP),
(-1.1234567891, (-2, 876543210), _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): with self.subTest(obj=obj, round=rnd, timespec=timespec):
self.assertEqual(pytime_object_to_timespec(obj, rnd), timespec) self.assertEqual(pytime_object_to_timespec(obj, rnd), timespec)
rnd = _PyTime.ROUND_DOWN rnd = _PyTime.ROUND_FLOOR
for invalid in self.invalid_values: for invalid in self.invalid_values:
self.assertRaises(OverflowError, self.assertRaises(OverflowError,
pytime_object_to_timespec, invalid, rnd) pytime_object_to_timespec, invalid, rnd)
...@@ -794,27 +839,34 @@ class TestPyTime_t(unittest.TestCase): ...@@ -794,27 +839,34 @@ class TestPyTime_t(unittest.TestCase):
UP = _PyTime.ROUND_UP UP = _PyTime.ROUND_UP
DOWN = _PyTime.ROUND_DOWN DOWN = _PyTime.ROUND_DOWN
FLOOR = _PyTime.ROUND_FLOOR FLOOR = _PyTime.ROUND_FLOOR
CEILING = _PyTime.ROUND_CEILING
for obj, ts, rnd in ( for obj, ts, rnd in (
# close to zero # close to zero
( 1e-10, 1, CEILING),
( 1e-10, 1, UP), ( 1e-10, 1, UP),
( 1e-10, 0, DOWN), ( 1e-10, 0, DOWN),
( 1e-10, 0, FLOOR), ( 1e-10, 0, FLOOR),
(-1e-10, 0, CEILING),
(-1e-10, 0, DOWN), (-1e-10, 0, DOWN),
(-1e-10, -1, UP), (-1e-10, -1, UP),
(-1e-10, -1, FLOOR), (-1e-10, -1, FLOOR),
# test rounding of the last nanosecond # test rounding of the last nanosecond
( 1.1234567899, 1123456790, CEILING),
( 1.1234567899, 1123456790, UP), ( 1.1234567899, 1123456790, UP),
( 1.1234567899, 1123456789, DOWN), ( 1.1234567899, 1123456789, DOWN),
( 1.1234567899, 1123456789, FLOOR), ( 1.1234567899, 1123456789, FLOOR),
(-1.1234567899, -1123456789, CEILING),
(-1.1234567899, -1123456789, DOWN), (-1.1234567899, -1123456789, DOWN),
(-1.1234567899, -1123456790, UP), (-1.1234567899, -1123456790, UP),
(-1.1234567899, -1123456790, FLOOR), (-1.1234567899, -1123456790, FLOOR),
# close to 1 second # close to 1 second
( 0.9999999999, 1000000000, CEILING),
( 0.9999999999, 1000000000, UP), ( 0.9999999999, 1000000000, UP),
( 0.9999999999, 999999999, DOWN), ( 0.9999999999, 999999999, DOWN),
( 0.9999999999, 999999999, FLOOR), ( 0.9999999999, 999999999, FLOOR),
(-0.9999999999, -999999999, CEILING),
(-0.9999999999, -999999999, DOWN), (-0.9999999999, -999999999, DOWN),
(-0.9999999999, -1000000000, UP), (-0.9999999999, -1000000000, UP),
(-0.9999999999, -1000000000, FLOOR), (-0.9999999999, -1000000000, FLOOR),
...@@ -890,19 +942,24 @@ class TestPyTime_t(unittest.TestCase): ...@@ -890,19 +942,24 @@ class TestPyTime_t(unittest.TestCase):
UP = _PyTime.ROUND_UP UP = _PyTime.ROUND_UP
DOWN = _PyTime.ROUND_DOWN DOWN = _PyTime.ROUND_DOWN
FLOOR = _PyTime.ROUND_FLOOR FLOOR = _PyTime.ROUND_FLOOR
CEILING = _PyTime.ROUND_CEILING
for ns, tv, rnd in ( for ns, tv, rnd in (
# nanoseconds # nanoseconds
(1, (0, 1), CEILING),
(1, (0, 1), UP), (1, (0, 1), UP),
(1, (0, 0), DOWN), (1, (0, 0), DOWN),
(1, (0, 0), FLOOR), (1, (0, 0), FLOOR),
(-1, (0, 0), CEILING),
(-1, (0, 0), DOWN), (-1, (0, 0), DOWN),
(-1, (-1, 999999), UP), (-1, (-1, 999999), UP),
(-1, (-1, 999999), FLOOR), (-1, (-1, 999999), FLOOR),
# seconds + nanoseconds # seconds + nanoseconds
(1234567001, (1, 234568), CEILING),
(1234567001, (1, 234568), UP), (1234567001, (1, 234568), UP),
(1234567001, (1, 234567), DOWN), (1234567001, (1, 234567), DOWN),
(1234567001, (1, 234567), FLOOR), (1234567001, (1, 234567), FLOOR),
(-1234567001, (-2, 765433), CEILING),
(-1234567001, (-2, 765433), DOWN), (-1234567001, (-2, 765433), DOWN),
(-1234567001, (-2, 765432), UP), (-1234567001, (-2, 765432), UP),
(-1234567001, (-2, 765432), FLOOR), (-1234567001, (-2, 765432), FLOOR),
......
...@@ -2635,7 +2635,7 @@ static int ...@@ -2635,7 +2635,7 @@ static int
check_time_rounding(int round) check_time_rounding(int round)
{ {
if (round != _PyTime_ROUND_DOWN && round != _PyTime_ROUND_UP 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"); PyErr_SetString(PyExc_ValueError, "invalid rounding");
return -1; return -1;
} }
......
...@@ -31,6 +31,8 @@ _PyTime_RoundTowardsPosInf(int is_neg, _PyTime_round_t round) ...@@ -31,6 +31,8 @@ _PyTime_RoundTowardsPosInf(int is_neg, _PyTime_round_t round)
{ {
if (round == _PyTime_ROUND_FLOOR) if (round == _PyTime_ROUND_FLOOR)
return 0; return 0;
if (round == _PyTime_ROUND_CEILING)
return 1;
return ((round == _PyTime_ROUND_UP) ^ is_neg); return ((round == _PyTime_ROUND_UP) ^ is_neg);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment