Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(35)

Delta Between Two Patch Sets: Modules/_datetimemodule.c

Issue 23517: datetime.utcfromtimestamp rounds results incorrectly
Left Patch Set: Created 4 years, 5 months ago
Right Patch Set: Created 4 years, 5 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« Lib/test/datetimetester.py ('K') | « Lib/test/datetimetester.py ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* C implementation for the date/time type documented at 1 /* C implementation for the date/time type documented at
2 * http://www.zope.org/Members/fdrake/DateTimeWiki/FrontPage 2 * http://www.zope.org/Members/fdrake/DateTimeWiki/FrontPage
3 */ 3 */
4 4
5 #include "Python.h" 5 #include "Python.h"
6 #include "structmember.h" 6 #include "structmember.h"
7 7
8 #include <time.h> 8 #include <time.h>
9 9
10 /* Differentiate between building the core module and building extension 10 /* Differentiate between building the core module and building extension
(...skipping 2125 matching lines...) Expand 10 before | Expand all | Expand 10 after
2136 y = accum("days", x, day, us_per_day, &leftover_us); 2136 y = accum("days", x, day, us_per_day, &leftover_us);
2137 CLEANUP; 2137 CLEANUP;
2138 } 2138 }
2139 if (week) { 2139 if (week) {
2140 y = accum("weeks", x, week, us_per_week, &leftover_us); 2140 y = accum("weeks", x, week, us_per_week, &leftover_us);
2141 CLEANUP; 2141 CLEANUP;
2142 } 2142 }
2143 if (leftover_us) { 2143 if (leftover_us) {
2144 /* Round to nearest whole # of us, and add into x. */ 2144 /* Round to nearest whole # of us, and add into x. */
2145 double whole_us = round(leftover_us); 2145 double whole_us = round(leftover_us);
2146 int x_is_odd;
2146 PyObject *temp; 2147 PyObject *temp;
2147 2148
2148 whole_us = _PyTime_RoundHalfUp(leftover_us); 2149 whole_us = round(leftover_us);
2150 if (fabs(whole_us - leftover_us) == 0.5) {
2151 /* We're exactly halfway between two integers. In order
2152 * to do round-half-to-even, we must determine whether x
2153 * is odd. Note that x is odd when it's last bit is 1. The
2154 * code below uses bitwise and operation to check the last
2155 * bit. */
2156 temp = PyNumber_And(x, one); /* temp <- x & 1 */
2157 if (temp == NULL) {
2158 Py_DECREF(x);
2159 goto Done;
2160 }
2161 x_is_odd = PyObject_IsTrue(temp);
2162 Py_DECREF(temp);
2163 if (x_is_odd == -1) {
2164 Py_DECREF(x);
2165 goto Done;
2166 }
2167 whole_us = 2.0 * round((leftover_us + x_is_odd) * 0.5) - x_is_odd;
2168 }
2149 2169
2150 temp = PyLong_FromLong((long)whole_us); 2170 temp = PyLong_FromLong((long)whole_us);
2151 2171
2152 if (temp == NULL) { 2172 if (temp == NULL) {
2153 Py_DECREF(x); 2173 Py_DECREF(x);
2154 goto Done; 2174 goto Done;
2155 } 2175 }
2156 y = PyNumber_Add(x, temp); 2176 y = PyNumber_Add(x, temp);
2157 Py_DECREF(temp); 2177 Py_DECREF(temp);
2158 CLEANUP; 2178 CLEANUP;
(...skipping 1927 matching lines...) Expand 10 before | Expand all | Expand 10 after
4086 tm->tm_year + 1900, 4106 tm->tm_year + 1900,
4087 tm->tm_mon + 1, 4107 tm->tm_mon + 1,
4088 tm->tm_mday, 4108 tm->tm_mday,
4089 tm->tm_hour, 4109 tm->tm_hour,
4090 tm->tm_min, 4110 tm->tm_min,
4091 tm->tm_sec, 4111 tm->tm_sec,
4092 us, 4112 us,
4093 tzinfo); 4113 tzinfo);
4094 } 4114 }
4095 4115
4116 /* Round to nearest with ties going to nearest even integer. */
4117 static double
4118 round_half_even(double x)
storchaka 2015/09/10 22:27:10 May be use lrint() if available?
4119 {
4120 double rounded = round(x);
4121 if (fabs(x-rounded) == 0.5)
4122 /* halfway case: round to even */
4123 rounded = 2.0*round(x/2.0);
4124 return rounded;
4125 }
4126
4096 /* Internal helper. 4127 /* Internal helper.
4097 * Build datetime from a Python timestamp. Pass localtime or gmtime for f, 4128 * Build datetime from a Python timestamp. Pass localtime or gmtime for f,
4098 * to control the interpretation of the timestamp. Since a double doesn't 4129 * to control the interpretation of the timestamp. Since a double doesn't
4099 * have enough bits to cover a datetime's full range of precision, it's 4130 * have enough bits to cover a datetime's full range of precision, it's
4100 * better to call datetime_from_timet_and_us provided you have a way 4131 * better to call datetime_from_timet_and_us provided you have a way
4101 * to get that much precision (e.g., C time() isn't good enough). 4132 * to get that much precision (e.g., C time() isn't good enough).
4102 */ 4133 */
4103 static PyObject * 4134 static PyObject *
4104 datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp, 4135 datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp,
4105 PyObject *tzinfo) 4136 PyObject *tzinfo)
4106 { 4137 {
4138 double dtime;
4107 time_t timet; 4139 time_t timet;
4108 long us; 4140 double fraction;
4109 4141 int us;
4110 if (_PyTime_ObjectToTimeval(timestamp, &timet, &us, _PyTime_ROUND_DOWN) == - 1) 4142
4111 return NULL; 4143 dtime = PyFloat_AsDouble(timestamp);
4112 return datetime_from_timet_and_us(cls, f, timet, (int)us, tzinfo); 4144 if (dtime == -1.0 && PyErr_Occurred())
4145 return NULL;
4146
4147 if (_PyTime_ObjectToTime_t(timestamp, &timet, _PyTime_ROUND_DOWN) < 0)
4148 return NULL;
4149
4150 fraction = dtime - (double)timet;
4151 us = (int)round_half_even(fraction * 1e6);
4152 if (us < 0) {
4153 us += 1000000;
4154 timet -= 1;
4155 }
4156 else if (us >= 1000000) {
4157 us -= 1000000;
4158 timet += 1;
4159 }
4160 return datetime_from_timet_and_us(cls, f, timet, us, tzinfo);
4113 } 4161 }
4114 4162
4115 /* Internal helper. 4163 /* Internal helper.
4116 * Build most accurate possible datetime for current time. Pass localtime or 4164 * Build most accurate possible datetime for current time. Pass localtime or
4117 * gmtime for f as appropriate. 4165 * gmtime for f as appropriate.
4118 */ 4166 */
4119 static PyObject * 4167 static PyObject *
4120 datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo) 4168 datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo)
4121 { 4169 {
4122 _PyTime_timeval t; 4170 _PyTime_timeval t;
(...skipping 1464 matching lines...) Expand 10 before | Expand all | Expand 10 after
5587 enough to say. 5635 enough to say.
5588 5636
5589 In any case, it's clear that the default fromutc() is strong enough to handle 5637 In any case, it's clear that the default fromutc() is strong enough to handle
5590 "almost all" time zones: so long as the standard offset is invariant, it 5638 "almost all" time zones: so long as the standard offset is invariant, it
5591 doesn't matter if daylight time transition points change from year to year, or 5639 doesn't matter if daylight time transition points change from year to year, or
5592 if daylight time is skipped in some years; it doesn't matter how large or 5640 if daylight time is skipped in some years; it doesn't matter how large or
5593 small dst() may get within its bounds; and it doesn't even matter if some 5641 small dst() may get within its bounds; and it doesn't even matter if some
5594 perverse time zone returns a negative dst()). So a breaking case must be 5642 perverse time zone returns a negative dst()). So a breaking case must be
5595 pretty bizarre, and a tzinfo subclass can override fromutc() if it is. 5643 pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
5596 --------------------------------------------------------------------------- */ 5644 --------------------------------------------------------------------------- */
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+