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

Side by Side Diff: Modules/_datetimemodule.c

Issue 23517: datetime.utcfromtimestamp rounds results incorrectly
Patch Set: Created 4 years, 6 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:
View unified diff | Download patch
« Lib/test/datetimetester.py ('K') | « Lib/test/datetimetester.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 4093 matching lines...) Expand 10 before | Expand all | Expand 10 after
4104 tm->tm_sec = 59; 4104 tm->tm_sec = 59;
4105 return PyObject_CallFunction(cls, "iiiiiiiO", 4105 return PyObject_CallFunction(cls, "iiiiiiiO",
4106 tm->tm_year + 1900, 4106 tm->tm_year + 1900,
4107 tm->tm_mon + 1, 4107 tm->tm_mon + 1,
4108 tm->tm_mday, 4108 tm->tm_mday,
4109 tm->tm_hour, 4109 tm->tm_hour,
4110 tm->tm_min, 4110 tm->tm_min,
4111 tm->tm_sec, 4111 tm->tm_sec,
4112 us, 4112 us,
4113 tzinfo); 4113 tzinfo);
4114 }
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;
4114 } 4125 }
4115 4126
4116 /* Internal helper. 4127 /* Internal helper.
4117 * 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,
4118 * 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
4119 * 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
4120 * 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
4121 * 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).
4122 */ 4133 */
4123 static PyObject * 4134 static PyObject *
4124 datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp, 4135 datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp,
4125 PyObject *tzinfo) 4136 PyObject *tzinfo)
4126 { 4137 {
4138 double dtime;
4127 time_t timet; 4139 time_t timet;
4128 long us; 4140 double fraction;
4141 int us;
4129 4142
4130 if (_PyTime_ObjectToTimeval(timestamp, &timet, &us, _PyTime_ROUND_DOWN) == - 1) 4143 dtime = PyFloat_AsDouble(timestamp);
4144 if (dtime == -1.0 && PyErr_Occurred())
4131 return NULL; 4145 return NULL;
4132 return datetime_from_timet_and_us(cls, f, timet, (int)us, tzinfo); 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);
4133 } 4161 }
4134 4162
4135 /* Internal helper. 4163 /* Internal helper.
4136 * Build most accurate possible datetime for current time. Pass localtime or 4164 * Build most accurate possible datetime for current time. Pass localtime or
4137 * gmtime for f as appropriate. 4165 * gmtime for f as appropriate.
4138 */ 4166 */
4139 static PyObject * 4167 static PyObject *
4140 datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo) 4168 datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo)
4141 { 4169 {
4142 _PyTime_timeval t; 4170 _PyTime_timeval t;
(...skipping 1464 matching lines...) Expand 10 before | Expand all | Expand 10 after
5607 enough to say. 5635 enough to say.
5608 5636
5609 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
5610 "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
5611 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
5612 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
5613 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
5614 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
5615 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.
5616 --------------------------------------------------------------------------- */ 5644 --------------------------------------------------------------------------- */
OLDNEW
« Lib/test/datetimetester.py ('K') | « Lib/test/datetimetester.py ('k') | no next file » | no next file with comments »

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