Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bcdd777

Browse files
committed
Issue #22117: Add _PyTime_ROUND_CEILING rounding method for timestamps
Add also more tests for ROUNd_FLOOR.
1 parent c4bb599 commit bcdd777

4 files changed

Lines changed: 68 additions & 6 deletions

File tree

Include/pytime.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ typedef enum {
3232
_PyTime_ROUND_UP,
3333
/* Round towards minus infinity (-inf).
3434
For example, used to read a clock. */
35-
_PyTime_ROUND_FLOOR
35+
_PyTime_ROUND_FLOOR,
36+
/* Round towards infinity (+inf).
37+
For example, used for timeout to wait "at least" N seconds. */
38+
_PyTime_ROUND_CEILING
3639
} _PyTime_round_t;
3740

3841
/* Convert a time_t to a PyLong. */

Lib/test/test_time.py

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,16 @@ class _PyTime(enum.IntEnum):
2828
ROUND_DOWN = 0
2929
# Round away from zero
3030
ROUND_UP = 1
31-
# Round towards -Infinity
31+
# Round towards minus infinity (-inf)
3232
ROUND_FLOOR = 2
33+
# Round towards infinity (+inf)
34+
ROUND_CEILING = 3
3335

3436
ALL_ROUNDING_METHODS = (
3537
_PyTime.ROUND_UP,
3638
_PyTime.ROUND_DOWN,
37-
_PyTime.ROUND_FLOOR)
39+
_PyTime.ROUND_FLOOR,
40+
_PyTime.ROUND_CEILING)
3841

3942

4043
class TimeTestCase(unittest.TestCase):
@@ -621,17 +624,31 @@ def test_time_t(self):
621624
(-1.9, -1, _PyTime.ROUND_DOWN),
622625
(1.0, 1, _PyTime.ROUND_DOWN),
623626
(1.9, 1, _PyTime.ROUND_DOWN),
627+
# Round towards minus infinity (-inf)
628+
(0, 0, _PyTime.ROUND_FLOOR),
629+
(-1, -1, _PyTime.ROUND_FLOOR),
630+
(-1.0, -1, _PyTime.ROUND_FLOOR),
631+
(-1.9, -2, _PyTime.ROUND_FLOOR),
632+
(1.0, 1, _PyTime.ROUND_FLOOR),
633+
(1.9, 1, _PyTime.ROUND_FLOOR),
624634
# Round away from zero
625635
(0, 0, _PyTime.ROUND_UP),
626636
(-1, -1, _PyTime.ROUND_UP),
627637
(-1.0, -1, _PyTime.ROUND_UP),
628638
(-1.9, -2, _PyTime.ROUND_UP),
629639
(1.0, 1, _PyTime.ROUND_UP),
630640
(1.9, 2, _PyTime.ROUND_UP),
641+
# Round towards infinity (+inf)
642+
(0, 0, _PyTime.ROUND_CEILING),
643+
(-1, -1, _PyTime.ROUND_CEILING),
644+
(-1.0, -1, _PyTime.ROUND_CEILING),
645+
(-1.9, -1, _PyTime.ROUND_CEILING),
646+
(1.0, 1, _PyTime.ROUND_CEILING),
647+
(1.9, 2, _PyTime.ROUND_CEILING),
631648
):
632649
self.assertEqual(pytime_object_to_time_t(obj, rnd), time_t)
633650

634-
rnd = _PyTime.ROUND_DOWN
651+
rnd = _PyTime.ROUND_FLOOR
635652
for invalid in self.invalid_values:
636653
self.assertRaises(OverflowError,
637654
pytime_object_to_time_t, invalid, rnd)
@@ -654,6 +671,20 @@ def test_timespec(self):
654671
(1.1234567899, (1, 123456789), _PyTime.ROUND_DOWN),
655672
(-1.1234567890, (-2, 876543211), _PyTime.ROUND_DOWN),
656673
(-1.1234567891, (-2, 876543211), _PyTime.ROUND_DOWN),
674+
# Round towards minus infinity (-inf)
675+
(0, (0, 0), _PyTime.ROUND_FLOOR),
676+
(-1, (-1, 0), _PyTime.ROUND_FLOOR),
677+
(-1.0, (-1, 0), _PyTime.ROUND_FLOOR),
678+
(1e-9, (0, 1), _PyTime.ROUND_FLOOR),
679+
(1e-10, (0, 0), _PyTime.ROUND_FLOOR),
680+
(-1e-9, (-1, 999999999), _PyTime.ROUND_FLOOR),
681+
(-1e-10, (-1, 999999999), _PyTime.ROUND_FLOOR),
682+
(-1.2, (-2, 800000000), _PyTime.ROUND_FLOOR),
683+
(0.9999999999, (0, 999999999), _PyTime.ROUND_FLOOR),
684+
(1.1234567890, (1, 123456789), _PyTime.ROUND_FLOOR),
685+
(1.1234567899, (1, 123456789), _PyTime.ROUND_FLOOR),
686+
(-1.1234567890, (-2, 876543211), _PyTime.ROUND_FLOOR),
687+
(-1.1234567891, (-2, 876543210), _PyTime.ROUND_FLOOR),
657688
# Round away from zero
658689
(0, (0, 0), _PyTime.ROUND_UP),
659690
(-1, (-1, 0), _PyTime.ROUND_UP),
@@ -668,11 +699,25 @@ def test_timespec(self):
668699
(1.1234567899, (1, 123456790), _PyTime.ROUND_UP),
669700
(-1.1234567890, (-2, 876543211), _PyTime.ROUND_UP),
670701
(-1.1234567891, (-2, 876543210), _PyTime.ROUND_UP),
702+
# Round towards infinity (+inf)
703+
(0, (0, 0), _PyTime.ROUND_CEILING),
704+
(-1, (-1, 0), _PyTime.ROUND_CEILING),
705+
(-1.0, (-1, 0), _PyTime.ROUND_CEILING),
706+
(1e-9, (0, 1), _PyTime.ROUND_CEILING),
707+
(1e-10, (0, 1), _PyTime.ROUND_CEILING),
708+
(-1e-9, (-1, 999999999), _PyTime.ROUND_CEILING),
709+
(-1e-10, (0, 0), _PyTime.ROUND_CEILING),
710+
(-1.2, (-2, 800000000), _PyTime.ROUND_CEILING),
711+
(0.9999999999, (1, 0), _PyTime.ROUND_CEILING),
712+
(1.1234567890, (1, 123456790), _PyTime.ROUND_CEILING),
713+
(1.1234567899, (1, 123456790), _PyTime.ROUND_CEILING),
714+
(-1.1234567890, (-2, 876543211), _PyTime.ROUND_CEILING),
715+
(-1.1234567891, (-2, 876543211), _PyTime.ROUND_CEILING),
671716
):
672717
with self.subTest(obj=obj, round=rnd, timespec=timespec):
673718
self.assertEqual(pytime_object_to_timespec(obj, rnd), timespec)
674719

675-
rnd = _PyTime.ROUND_DOWN
720+
rnd = _PyTime.ROUND_FLOOR
676721
for invalid in self.invalid_values:
677722
self.assertRaises(OverflowError,
678723
pytime_object_to_timespec, invalid, rnd)
@@ -794,27 +839,34 @@ def test_FromSecondsObject(self):
794839
UP = _PyTime.ROUND_UP
795840
DOWN = _PyTime.ROUND_DOWN
796841
FLOOR = _PyTime.ROUND_FLOOR
842+
CEILING = _PyTime.ROUND_CEILING
797843
for obj, ts, rnd in (
798844
# close to zero
845+
( 1e-10, 1, CEILING),
799846
( 1e-10, 1, UP),
800847
( 1e-10, 0, DOWN),
801848
( 1e-10, 0, FLOOR),
849+
(-1e-10, 0, CEILING),
802850
(-1e-10, 0, DOWN),
803851
(-1e-10, -1, UP),
804852
(-1e-10, -1, FLOOR),
805853

806854
# test rounding of the last nanosecond
855+
( 1.1234567899, 1123456790, CEILING),
807856
( 1.1234567899, 1123456790, UP),
808857
( 1.1234567899, 1123456789, DOWN),
809858
( 1.1234567899, 1123456789, FLOOR),
859+
(-1.1234567899, -1123456789, CEILING),
810860
(-1.1234567899, -1123456789, DOWN),
811861
(-1.1234567899, -1123456790, UP),
812862
(-1.1234567899, -1123456790, FLOOR),
813863

814864
# close to 1 second
865+
( 0.9999999999, 1000000000, CEILING),
815866
( 0.9999999999, 1000000000, UP),
816867
( 0.9999999999, 999999999, DOWN),
817868
( 0.9999999999, 999999999, FLOOR),
869+
(-0.9999999999, -999999999, CEILING),
818870
(-0.9999999999, -999999999, DOWN),
819871
(-0.9999999999, -1000000000, UP),
820872
(-0.9999999999, -1000000000, FLOOR),
@@ -890,19 +942,24 @@ def test_timeval(self):
890942
UP = _PyTime.ROUND_UP
891943
DOWN = _PyTime.ROUND_DOWN
892944
FLOOR = _PyTime.ROUND_FLOOR
945+
CEILING = _PyTime.ROUND_CEILING
893946
for ns, tv, rnd in (
894947
# nanoseconds
948+
(1, (0, 1), CEILING),
895949
(1, (0, 1), UP),
896950
(1, (0, 0), DOWN),
897951
(1, (0, 0), FLOOR),
952+
(-1, (0, 0), CEILING),
898953
(-1, (0, 0), DOWN),
899954
(-1, (-1, 999999), UP),
900955
(-1, (-1, 999999), FLOOR),
901956

902957
# seconds + nanoseconds
958+
(1234567001, (1, 234568), CEILING),
903959
(1234567001, (1, 234568), UP),
904960
(1234567001, (1, 234567), DOWN),
905961
(1234567001, (1, 234567), FLOOR),
962+
(-1234567001, (-2, 765433), CEILING),
906963
(-1234567001, (-2, 765433), DOWN),
907964
(-1234567001, (-2, 765432), UP),
908965
(-1234567001, (-2, 765432), FLOOR),

Modules/_testcapimodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2635,7 +2635,7 @@ static int
26352635
check_time_rounding(int round)
26362636
{
26372637
if (round != _PyTime_ROUND_DOWN && round != _PyTime_ROUND_UP
2638-
&& round != _PyTime_ROUND_FLOOR) {
2638+
&& round != _PyTime_ROUND_FLOOR && round != _PyTime_ROUND_CEILING) {
26392639
PyErr_SetString(PyExc_ValueError, "invalid rounding");
26402640
return -1;
26412641
}

Python/pytime.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ _PyTime_RoundTowardsPosInf(int is_neg, _PyTime_round_t round)
3131
{
3232
if (round == _PyTime_ROUND_FLOOR)
3333
return 0;
34+
if (round == _PyTime_ROUND_CEILING)
35+
return 1;
3436
return ((round == _PyTime_ROUND_UP) ^ is_neg);
3537
}
3638

0 commit comments

Comments
 (0)