cpython: abeb625b20c2 (original) (raw)
--- a/Include/pytime.h +++ b/Include/pytime.h @@ -30,7 +30,10 @@ typedef enum { _PyTime_ROUND_FLOOR=0, /* Round towards infinity (+inf). For example, used for timeout to wait "at least" N seconds. */
- _PyTime_ROUND_CEILING=1,
- /* Round to nearest with ties going away from zero.
For example, used to round from a Python float. */[](#l1.10)
- _PyTime_ROUND_HALF_UP
} _PyTime_round_t; /* Convert a time_t to a PyLong. */
--- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -30,8 +30,11 @@ class _PyTime(enum.IntEnum): ROUND_FLOOR = 0 # Round towards infinity (+inf) ROUND_CEILING = 1
-ALL_ROUNDING_METHODS = (_PyTime.ROUND_FLOOR, _PyTime.ROUND_CEILING) +ALL_ROUNDING_METHODS = (_PyTime.ROUND_FLOOR, _PyTime.ROUND_CEILING,
_PyTime.ROUND_HALF_UP)[](#l2.12)
class TimeTestCase(unittest.TestCase): @@ -753,11 +756,11 @@ class TestPyTime_t(unittest.TestCase): (123.0, 123 * SEC_TO_NS), (-7.0, -7 * SEC_TO_NS),
# nanosecond are kept for value <= 2^23 seconds[](#l2.20)
# nanosecond are kept for value <= 2^23 seconds,[](#l2.21)
# except 2**23-1e-9 with HALF_UP[](#l2.22) (2**22 - 1e-9, 4194303999999999),[](#l2.23) (2**22, 4194304000000000),[](#l2.24) (2**22 + 1e-9, 4194304000000001),[](#l2.25)
(2**23 - 1e-9, 8388607999999999),[](#l2.26) (2**23, 8388608000000000),[](#l2.27)
# start loosing precision for value > 2^23 seconds @@ -790,24 +793,36 @@ class TestPyTime_t(unittest.TestCase): # Conversion giving different results depending on the rounding method FLOOR = _PyTime.ROUND_FLOOR CEILING = _PyTime.ROUND_CEILING
HALF_UP = _PyTime.ROUND_HALF_UP[](#l2.34) for obj, ts, rnd in ([](#l2.35) # close to zero[](#l2.36) ( 1e-10, 0, FLOOR),[](#l2.37) ( 1e-10, 1, CEILING),[](#l2.38)
( 1e-10, 0, HALF_UP),[](#l2.39) (-1e-10, -1, FLOOR),[](#l2.40) (-1e-10, 0, CEILING),[](#l2.41)
(-1e-10, 0, HALF_UP),[](#l2.42)
# test rounding of the last nanosecond ( 1.1234567899, 1123456789, FLOOR), ( 1.1234567899, 1123456790, CEILING),
( 1.1234567899, 1123456790, HALF_UP),[](#l2.47) (-1.1234567899, -1123456790, FLOOR),[](#l2.48) (-1.1234567899, -1123456789, CEILING),[](#l2.49)
(-1.1234567899, -1123456790, HALF_UP),[](#l2.50)
# close to 1 second ( 0.9999999999, 999999999, FLOOR), ( 0.9999999999, 1000000000, CEILING),
( 0.9999999999, 1000000000, HALF_UP),[](#l2.55) (-0.9999999999, -1000000000, FLOOR),[](#l2.56) (-0.9999999999, -999999999, CEILING),[](#l2.57)
(-0.9999999999, -1000000000, HALF_UP),[](#l2.58)
# close to 2^23 seconds[](#l2.60)
(2**23 - 1e-9, 8388607999999999, FLOOR),[](#l2.61)
(2**23 - 1e-9, 8388607999999999, CEILING),[](#l2.62)
(2**23 - 1e-9, 8388608000000000, HALF_UP),[](#l2.63) ):[](#l2.64) with self.subTest(obj=obj, round=rnd, timestamp=ts):[](#l2.65) self.assertEqual(PyTime_FromSecondsObject(obj, rnd), ts)[](#l2.66)
@@ -875,18 +890,33 @@ class TestPyTime_t(unittest.TestCase): FLOOR = _PyTime.ROUND_FLOOR CEILING = _PyTime.ROUND_CEILING
HALF_UP = _PyTime.ROUND_HALF_UP[](#l2.71) for ns, tv, rnd in ([](#l2.72) # nanoseconds[](#l2.73) (1, (0, 0), FLOOR),[](#l2.74) (1, (0, 1), CEILING),[](#l2.75)
(1, (0, 0), HALF_UP),[](#l2.76) (-1, (-1, 999999), FLOOR),[](#l2.77) (-1, (0, 0), CEILING),[](#l2.78)
(-1, (0, 0), HALF_UP),[](#l2.79)
# seconds + nanoseconds (1234567001, (1, 234567), FLOOR), (1234567001, (1, 234568), CEILING),
(1234567001, (1, 234567), HALF_UP),[](#l2.84) (-1234567001, (-2, 765432), FLOOR),[](#l2.85) (-1234567001, (-2, 765433), CEILING),[](#l2.86)
(-1234567001, (-2, 765433), HALF_UP),[](#l2.87)
# half up[](#l2.89)
(499, (0, 0), HALF_UP),[](#l2.90)
(500, (0, 1), HALF_UP),[](#l2.91)
(501, (0, 1), HALF_UP),[](#l2.92)
(999, (0, 1), HALF_UP),[](#l2.93)
(-499, (0, 0), HALF_UP),[](#l2.94)
(-500, (0, 0), HALF_UP),[](#l2.95)
(-501, (-1, 999999), HALF_UP),[](#l2.96)
(-999, (-1, 999999), HALF_UP),[](#l2.97) ):[](#l2.98) with self.subTest(nanoseconds=ns, timeval=tv, round=rnd):[](#l2.99) self.assertEqual(PyTime_AsTimeval(ns, rnd), tv)[](#l2.100)
@@ -929,18 +959,33 @@ class TestPyTime_t(unittest.TestCase): FLOOR = _PyTime.ROUND_FLOOR CEILING = _PyTime.ROUND_CEILING
HALF_UP = _PyTime.ROUND_HALF_UP[](#l2.105) for ns, ms, rnd in ([](#l2.106) # nanoseconds[](#l2.107) (1, 0, FLOOR),[](#l2.108) (1, 1, CEILING),[](#l2.109)
(1, 0, HALF_UP),[](#l2.110) (-1, 0, FLOOR),[](#l2.111) (-1, -1, CEILING),[](#l2.112)
(-1, 0, HALF_UP),[](#l2.113)
# seconds + nanoseconds (1234 * MS_TO_NS + 1, 1234, FLOOR), (1234 * MS_TO_NS + 1, 1235, CEILING),
(1234 * MS_TO_NS + 1, 1234, HALF_UP),[](#l2.118) (-1234 * MS_TO_NS - 1, -1234, FLOOR),[](#l2.119) (-1234 * MS_TO_NS - 1, -1235, CEILING),[](#l2.120)
(-1234 * MS_TO_NS - 1, -1234, HALF_UP),[](#l2.121)
# half up[](#l2.123)
(499999, 0, HALF_UP),[](#l2.124)
(499999, 0, HALF_UP),[](#l2.125)
(500000, 1, HALF_UP),[](#l2.126)
(999999, 1, HALF_UP),[](#l2.127)
(-499999, 0, HALF_UP),[](#l2.128)
(-500000, -1, HALF_UP),[](#l2.129)
(-500001, -1, HALF_UP),[](#l2.130)
(-999999, -1, HALF_UP),[](#l2.131) ):[](#l2.132) with self.subTest(nanoseconds=ns, milliseconds=ms, round=rnd):[](#l2.133) self.assertEqual(PyTime_AsMilliseconds(ns, rnd), ms)[](#l2.134)
@@ -966,18 +1011,31 @@ class TestPyTime_t(unittest.TestCase): FLOOR = _PyTime.ROUND_FLOOR CEILING = _PyTime.ROUND_CEILING
HALF_UP = _PyTime.ROUND_HALF_UP[](#l2.139) for ns, ms, rnd in ([](#l2.140) # nanoseconds[](#l2.141) (1, 0, FLOOR),[](#l2.142) (1, 1, CEILING),[](#l2.143)
(1, 0, HALF_UP),[](#l2.144) (-1, 0, FLOOR),[](#l2.145) (-1, -1, CEILING),[](#l2.146)
(-1, 0, HALF_UP),[](#l2.147)
# seconds + nanoseconds (1234 * US_TO_NS + 1, 1234, FLOOR), (1234 * US_TO_NS + 1, 1235, CEILING),
(1234 * US_TO_NS + 1, 1234, HALF_UP),[](#l2.152) (-1234 * US_TO_NS - 1, -1234, FLOOR),[](#l2.153) (-1234 * US_TO_NS - 1, -1235, CEILING),[](#l2.154)
(-1234 * US_TO_NS - 1, -1234, HALF_UP),[](#l2.155)
# half up[](#l2.157)
(1499, 1, HALF_UP),[](#l2.158)
(1500, 2, HALF_UP),[](#l2.159)
(1501, 2, HALF_UP),[](#l2.160)
(-1499, -1, HALF_UP),[](#l2.161)
(-1500, -2, HALF_UP),[](#l2.162)
(-1501, -2, HALF_UP),[](#l2.163) ):[](#l2.164) with self.subTest(nanoseconds=ns, milliseconds=ms, round=rnd):[](#l2.165) self.assertEqual(PyTime_AsMicroseconds(ns, rnd), ms)[](#l2.166)
--- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2646,7 +2646,9 @@ run_in_subinterp(PyObject *self, PyObjec static int check_time_rounding(int round) {
- if (round != _PyTime_ROUND_FLOOR
&& round != _PyTime_ROUND_CEILING[](#l3.9)
}&& round != _PyTime_ROUND_HALF_UP) {[](#l3.10) PyErr_SetString(PyExc_ValueError, "invalid rounding");[](#l3.11) return -1;[](#l3.12)
--- a/Python/pytime.c +++ b/Python/pytime.c @@ -60,6 +60,17 @@ PyObject * #endif } +static double +_PyTime_RoundHalfUp(double x) +{
+} + + static int _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator, double denominator, _PyTime_round_t round) @@ -75,7 +86,9 @@ static int } floatpart *= denominator;
- if (round == _PyTime_ROUND_HALF_UP)
floatpart = _PyTime_RoundHalfUp(floatpart);[](#l4.27)
- else if (round == _PyTime_ROUND_CEILING) { floatpart = ceil(floatpart); if (floatpart >= denominator) { floatpart = 0.0;
@@ -124,7 +137,9 @@ int double d, intpart, err; d = PyFloat_AsDouble(obj);
if (round == _PyTime_ROUND_CEILING)[](#l4.36)
if (round == _PyTime_ROUND_HALF_UP)[](#l4.37)
d = _PyTime_RoundHalfUp(d);[](#l4.38)
else if (round == _PyTime_ROUND_CEILING)[](#l4.39) d = ceil(d);[](#l4.40) else[](#l4.41) d = floor(d);[](#l4.42)
@@ -247,7 +262,9 @@ static int d = value; d *= to_nanoseconds;
- if (round == _PyTime_ROUND_HALF_UP)
d = _PyTime_RoundHalfUp(d);[](#l4.49)
- else if (round == _PyTime_ROUND_CEILING) d = ceil(d); else d = floor(d);
@@ -333,7 +350,19 @@ static _PyTime_t _PyTime_Divide(_PyTime_t t, _PyTime_t k, _PyTime_round_t round) { assert(k > 1);
- if (round == _PyTime_ROUND_HALF_UP) {
_PyTime_t x, r;[](#l4.60)
x = t / k;[](#l4.61)
r = t % k;[](#l4.62)
if (Py_ABS(r) >= k / 2) {[](#l4.63)
if (t >= 0)[](#l4.64)
x++;[](#l4.65)
else[](#l4.66)
x--;[](#l4.67)
}[](#l4.68)
return x;[](#l4.69)
- }
- else if (round == _PyTime_ROUND_CEILING) { if (t >= 0) return (t + k - 1) / k; else
@@ -359,8 +388,10 @@ static int _PyTime_AsTimeval_impl(_PyTime_t t, struct timeval *tv, _PyTime_round_t round, int raise) {
secs = t / SEC_TO_NS; ns = t % SEC_TO_NS; @@ -392,20 +423,33 @@ static int res = -1; #endif
- if (round == _PyTime_ROUND_HALF_UP) {
_PyTime_t r;[](#l4.93)
usec = (int)(ns / k);[](#l4.94)
r = ns % k;[](#l4.95)
if (Py_ABS(r) >= k / 2) {[](#l4.96)
if (ns >= 0)[](#l4.97)
usec++;[](#l4.98)
else[](#l4.99)
usec--;[](#l4.100)
}[](#l4.101)
- }
- else if (round == _PyTime_ROUND_CEILING)
elseusec = (int)((ns + k - 1) / k);[](#l4.104)
tv->tv_usec = (int)(ns / US_TO_NS);[](#l4.106)
usec = (int)(ns / k);[](#l4.107)