Issue #22117: Add _PyTime_ROUND_CEILING rounding method for timestamps
Add also more tests for ROUNd_FLOOR.
This commit is contained in:
parent
c4bb599be0
commit
bcdd777d3c
@ -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):
|
|||||||
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):
|
|||||||
(-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):
|
|||||||
(-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):
|
|||||||
(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):
|
|||||||
(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):
|
|||||||
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):
|
|||||||
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
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user