diff options
Diffstat (limited to 'Modules/_datetimemodule.c')
| -rw-r--r-- | Modules/_datetimemodule.c | 274 |
1 files changed, 191 insertions, 83 deletions
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index fa231d9..6084ffa 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -16,6 +16,12 @@ #include "datetime.h" #undef Py_BUILD_CORE +/*[clinic input] +module datetime +class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=78142cb64b9e98bc]*/ + /* We require that C int be at least 32 bits, and use int virtually * everywhere. In just a few cases we use a temp long, where a Python * API returns a C long. In such cases, we have to ensure that the @@ -104,6 +110,11 @@ static PyTypeObject PyDateTime_TimeType; static PyTypeObject PyDateTime_TZInfoType; static PyTypeObject PyDateTime_TimeZoneType; +_Py_IDENTIFIER(as_integer_ratio); +_Py_IDENTIFIER(fromutc); +_Py_IDENTIFIER(isoformat); +_Py_IDENTIFIER(strftime); + /* --------------------------------------------------------------------------- * Math utilities. */ @@ -140,19 +151,6 @@ divmod(int x, int y, int *r) return quo; } -/* Round a double to the nearest long. |x| must be small enough to fit - * in a C long; this is not checked. - */ -static long -round_to_long(double x) -{ - if (x >= 0.0) - x = floor(x + 0.5); - else - x = ceil(x - 0.5); - return (long)x; -} - /* Nearest integer to m / n for integers m and n. Half-integer results * are rounded to even. */ @@ -615,7 +613,7 @@ time_alloc(PyTypeObject *type, Py_ssize_t aware) sizeof(_PyDateTime_BaseTime)); if (self == NULL) return (PyObject *)PyErr_NoMemory(); - PyObject_INIT(self, type); + (void)PyObject_INIT(self, type); return self; } @@ -630,7 +628,7 @@ datetime_alloc(PyTypeObject *type, Py_ssize_t aware) sizeof(_PyDateTime_BaseDateTime)); if (self == NULL) return (PyObject *)PyErr_NoMemory(); - PyObject_INIT(self, type); + (void)PyObject_INIT(self, type); return self; } @@ -899,11 +897,11 @@ call_tzinfo_method(PyObject *tzinfo, char *name, PyObject *tzinfoarg) } } else { - Py_DECREF(offset); PyErr_Format(PyExc_TypeError, "tzinfo.%s() must return None or " "timedelta, not '%.200s'", name, Py_TYPE(offset)->tp_name); + Py_DECREF(offset); return NULL; } @@ -1290,8 +1288,6 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, goto Done; format = PyUnicode_FromString(PyBytes_AS_STRING(newfmt)); if (format != NULL) { - _Py_IDENTIFIER(strftime); - result = _PyObject_CallMethodId(time, &PyId_strftime, "OO", format, timetuple, NULL); Py_DECREF(format); @@ -1397,7 +1393,7 @@ cmperror(PyObject *a, PyObject *b) */ /* Conversion factors. */ -static PyObject *us_per_us = NULL; /* 1 */ +static PyObject *one = NULL; /* 1 */ static PyObject *us_per_ms = NULL; /* 1000 */ static PyObject *us_per_second = NULL; /* 1000000 */ static PyObject *us_per_minute = NULL; /* 1e6 * 60 as Python int */ @@ -1579,7 +1575,6 @@ multiply_float_timedelta(PyObject *floatobj, PyDateTime_Delta *delta) PyObject *result = NULL; PyObject *pyus_in = NULL, *temp, *pyus_out; PyObject *ratio = NULL; - _Py_IDENTIFIER(as_integer_ratio); pyus_in = delta_to_microseconds(delta); if (pyus_in == NULL) @@ -1678,7 +1673,6 @@ truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *f) PyObject *result = NULL; PyObject *pyus_in = NULL, *temp, *pyus_out; PyObject *ratio = NULL; - _Py_IDENTIFIER(as_integer_ratio); pyus_in = delta_to_microseconds(delta); if (pyus_in == NULL) @@ -2119,7 +2113,7 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) goto Done if (us) { - y = accum("microseconds", x, us, us_per_us, &leftover_us); + y = accum("microseconds", x, us, one, &leftover_us); CLEANUP; } if (ms) { @@ -2148,7 +2142,33 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) } if (leftover_us) { /* Round to nearest whole # of us, and add into x. */ - PyObject *temp = PyLong_FromLong(round_to_long(leftover_us)); + double whole_us = round(leftover_us); + int x_is_odd; + PyObject *temp; + + whole_us = round(leftover_us); + if (fabs(whole_us - leftover_us) == 0.5) { + /* We're exactly halfway between two integers. In order + * to do round-half-to-even, we must determine whether x + * is odd. Note that x is odd when it's last bit is 1. The + * code below uses bitwise and operation to check the last + * bit. */ + temp = PyNumber_And(x, one); /* temp <- x & 1 */ + if (temp == NULL) { + Py_DECREF(x); + goto Done; + } + x_is_odd = PyObject_IsTrue(temp); + Py_DECREF(temp); + if (x_is_odd == -1) { + Py_DECREF(x); + goto Done; + } + whole_us = 2.0 * round((leftover_us + x_is_odd) * 0.5) - x_is_odd; + } + + temp = PyLong_FromLong((long)whole_us); + if (temp == NULL) { Py_DECREF(x); goto Done; @@ -2239,22 +2259,14 @@ delta_total_seconds(PyObject *self) { PyObject *total_seconds; PyObject *total_microseconds; - PyObject *one_million; total_microseconds = delta_to_microseconds((PyDateTime_Delta *)self); if (total_microseconds == NULL) return NULL; - one_million = PyLong_FromLong(1000000L); - if (one_million == NULL) { - Py_DECREF(total_microseconds); - return NULL; - } - - total_seconds = PyNumber_TrueDivide(total_microseconds, one_million); + total_seconds = PyNumber_TrueDivide(total_microseconds, us_per_second); Py_DECREF(total_microseconds); - Py_DECREF(one_million); return total_seconds; } @@ -2447,7 +2459,7 @@ date_local_from_object(PyObject *cls, PyObject *obj) struct tm *tm; time_t t; - if (_PyTime_ObjectToTime_t(obj, &t) == -1) + if (_PyTime_ObjectToTime_t(obj, &t, _PyTime_ROUND_DOWN) == -1) return NULL; tm = localtime(&t); @@ -2630,8 +2642,6 @@ date_isoformat(PyDateTime_Date *self) static PyObject * date_str(PyDateTime_Date *self) { - _Py_IDENTIFIER(isoformat); - return _PyObject_CallMethodId((PyObject *)self, &PyId_isoformat, "()"); } @@ -2671,7 +2681,6 @@ static PyObject * date_format(PyDateTime_Date *self, PyObject *args) { PyObject *format; - _Py_IDENTIFIER(strftime); if (!PyArg_ParseTuple(args, "U:__format__", &format)) return NULL; @@ -3031,7 +3040,7 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) goto Fail; if (dst == Py_None) goto Inconsistent; - if (delta_bool(delta) != 0) { + if (delta_bool((PyDateTime_Delta *)dst) != 0) { PyObject *temp = result; result = add_datetime_timedelta((PyDateTime_DateTime *)result, (PyDateTime_Delta *)dst, 1); @@ -3215,10 +3224,10 @@ timezone_richcompare(PyDateTime_TimeZone *self, if (op != Py_EQ && op != Py_NE) Py_RETURN_NOTIMPLEMENTED; if (Py_TYPE(other) != &PyDateTime_TimeZoneType) { - if (op == Py_EQ) - Py_RETURN_FALSE; - else - Py_RETURN_TRUE; + if (op == Py_EQ) + Py_RETURN_FALSE; + else + Py_RETURN_TRUE; } return delta_richcompare(self->offset, other->offset, op); } @@ -3588,8 +3597,6 @@ time_repr(PyDateTime_Time *self) static PyObject * time_str(PyDateTime_Time *self) { - _Py_IDENTIFIER(isoformat); - return _PyObject_CallMethodId((PyObject *)self, &PyId_isoformat, "()"); } @@ -4106,6 +4113,44 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, tzinfo); } +static time_t +_PyTime_DoubleToTimet(double x) +{ + time_t result; + double diff; + + result = (time_t)x; + /* How much info did we lose? time_t may be an integral or + * floating type, and we don't know which. If it's integral, + * we don't know whether C truncates, rounds, returns the floor, + * etc. If we lost a second or more, the C rounding is + * unreasonable, or the input just doesn't fit in a time_t; + * call it an error regardless. Note that the original cast to + * time_t can cause a C error too, but nothing we can do to + * worm around that. + */ + diff = x - (double)result; + if (diff <= -1.0 || diff >= 1.0) { + PyErr_SetString(PyExc_OverflowError, + "timestamp out of range for platform time_t"); + result = (time_t)-1; + } + return result; +} + +/* Round a double to the nearest long. |x| must be small enough to fit + * in a C long; this is not checked. + */ +static double +_PyTime_RoundHalfEven(double x) +{ + double rounded = round(x); + if (fabs(x-rounded) == 0.5) + /* halfway case: round to even */ + rounded = 2.0*round(x/2.0); + return rounded; +} + /* Internal helper. * Build datetime from a Python timestamp. Pass localtime or gmtime for f, * to control the interpretation of the timestamp. Since a double doesn't @@ -4114,15 +4159,32 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, * to get that much precision (e.g., C time() isn't good enough). */ static PyObject * -datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp, +datetime_from_timestamp(PyObject *cls, TM_FUNC f, double timestamp, PyObject *tzinfo) { time_t timet; - long us; + double fraction; + int us; - if (_PyTime_ObjectToTimeval(timestamp, &timet, &us) == -1) + timet = _PyTime_DoubleToTimet(timestamp); + if (timet == (time_t)-1 && PyErr_Occurred()) return NULL; - return datetime_from_timet_and_us(cls, f, timet, (int)us, tzinfo); + fraction = timestamp - (double)timet; + us = (int)_PyTime_RoundHalfEven(fraction * 1e6); + if (us < 0) { + /* Truncation towards zero is not what we wanted + for negative numbers (Python's mod semantics) */ + timet -= 1; + us += 1000000; + } + /* If timestamp is less than one microsecond smaller than a + * full second, round up. Otherwise, ValueErrors are raised + * for some floats. */ + if (us == 1000000) { + timet += 1; + us = 0; + } + return datetime_from_timet_and_us(cls, f, timet, us, tzinfo); } /* Internal helper. @@ -4138,31 +4200,73 @@ datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo) tzinfo); } -/* Return best possible local time -- this isn't constrained by the - * precision of a timestamp. - */ +/*[clinic input] + +@classmethod +datetime.datetime.now + + tz: object = None + Timezone object. + +Returns new datetime object representing current time local to tz. + +If no tz is specified, uses local timezone. +[clinic start generated code]*/ + +PyDoc_STRVAR(datetime_datetime_now__doc__, +"now($type, /, tz=None)\n" +"--\n" +"\n" +"Returns new datetime object representing current time local to tz.\n" +"\n" +" tz\n" +" Timezone object.\n" +"\n" +"If no tz is specified, uses local timezone."); + +#define DATETIME_DATETIME_NOW_METHODDEF \ + {"now", (PyCFunction)datetime_datetime_now, METH_VARARGS|METH_KEYWORDS|METH_CLASS, datetime_datetime_now__doc__}, + +static PyObject * +datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz); + +static PyObject * +datetime_datetime_now(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"tz", NULL}; + PyObject *tz = Py_None; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|O:now", _keywords, + &tz)) + goto exit; + return_value = datetime_datetime_now_impl(type, tz); + +exit: + return return_value; +} + static PyObject * -datetime_now(PyObject *cls, PyObject *args, PyObject *kw) +datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) +/*[clinic end generated code: output=583c5637e3c843fa input=80d09869c5267d00]*/ { PyObject *self; - PyObject *tzinfo = Py_None; - static char *keywords[] = {"tz", NULL}; - if (! PyArg_ParseTupleAndKeywords(args, kw, "|O:now", keywords, - &tzinfo)) - return NULL; - if (check_tzinfo_subclass(tzinfo) < 0) + /* Return best possible local time -- this isn't constrained by the + * precision of a timestamp. + */ + if (check_tzinfo_subclass(tz) < 0) return NULL; - self = datetime_best_possible(cls, - tzinfo == Py_None ? localtime : gmtime, - tzinfo); - if (self != NULL && tzinfo != Py_None) { + self = datetime_best_possible((PyObject *)type, + tz == Py_None ? localtime : gmtime, + tz); + if (self != NULL && tz != Py_None) { /* Convert UTC to tzinfo's zone. */ PyObject *temp = self; - _Py_IDENTIFIER(fromutc); - self = _PyObject_CallMethodId(tzinfo, &PyId_fromutc, "O", self); + self = _PyObject_CallMethodId(tz, &PyId_fromutc, "O", self); Py_DECREF(temp); } return self; @@ -4182,11 +4286,11 @@ static PyObject * datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) { PyObject *self; - PyObject *timestamp; + double timestamp; PyObject *tzinfo = Py_None; static char *keywords[] = {"timestamp", "tz", NULL}; - if (! PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp", + if (! PyArg_ParseTupleAndKeywords(args, kw, "d|O:fromtimestamp", keywords, ×tamp, &tzinfo)) return NULL; if (check_tzinfo_subclass(tzinfo) < 0) @@ -4199,7 +4303,6 @@ datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) if (self != NULL && tzinfo != Py_None) { /* Convert UTC to tzinfo's zone. */ PyObject *temp = self; - _Py_IDENTIFIER(fromutc); self = _PyObject_CallMethodId(tzinfo, &PyId_fromutc, "O", self); Py_DECREF(temp); @@ -4211,10 +4314,10 @@ datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) static PyObject * datetime_utcfromtimestamp(PyObject *cls, PyObject *args) { - PyObject *timestamp; + double timestamp; PyObject *result = NULL; - if (PyArg_ParseTuple(args, "O:utcfromtimestamp", ×tamp)) + if (PyArg_ParseTuple(args, "d:utcfromtimestamp", ×tamp)) result = datetime_from_timestamp(cls, gmtime, timestamp, Py_None); return result; @@ -4421,6 +4524,9 @@ datetime_subtract(PyObject *left, PyObject *right) delta_us = DATE_GET_MICROSECOND(left) - DATE_GET_MICROSECOND(right); result = new_delta(delta_d, delta_s, delta_us, 1); + if (result == NULL) + return NULL; + if (offdiff != NULL) { PyObject *temp = result; result = delta_subtract(result, offdiff); @@ -4482,8 +4588,6 @@ datetime_repr(PyDateTime_DateTime *self) static PyObject * datetime_str(PyDateTime_DateTime *self) { - _Py_IDENTIFIER(isoformat); - return _PyObject_CallMethodId((PyObject *)self, &PyId_isoformat, "(s)", " "); } @@ -4749,7 +4853,7 @@ local_timezone(PyDateTime_DateTime *utc_time) goto error; } result = new_timezone(delta, nameo); - Py_DECREF(nameo); + Py_XDECREF(nameo); error: Py_DECREF(delta); return result; @@ -4762,11 +4866,10 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) PyObject *offset; PyObject *temp; PyObject *tzinfo = Py_None; - _Py_IDENTIFIER(fromutc); static char *keywords[] = {"tz", NULL}; if (! PyArg_ParseTupleAndKeywords(args, kw, "|O:astimezone", keywords, - &tzinfo)) + &tzinfo)) return NULL; if (check_tzinfo_subclass(tzinfo) == -1) @@ -4873,9 +4976,16 @@ datetime_timestamp(PyDateTime_DateTime *self) time.tm_wday = -1; time.tm_isdst = -1; timestamp = mktime(&time); - /* Return value of -1 does not necessarily mean an error, but tm_wday - * cannot remain set to -1 if mktime succeeded. */ - if (timestamp == (time_t)(-1) && time.tm_wday == -1) { + if (timestamp == (time_t)(-1) +#ifndef _AIX + /* Return value of -1 does not necessarily mean an error, + * but tm_wday cannot remain set to -1 if mktime succeeded. */ + && time.tm_wday == -1 +#else + /* on AIX, tm_wday is always sets, even on error */ +#endif + ) + { PyErr_SetString(PyExc_OverflowError, "timestamp out of range"); return NULL; @@ -4989,9 +5099,7 @@ static PyMethodDef datetime_methods[] = { /* Class methods: */ - {"now", (PyCFunction)datetime_now, - METH_VARARGS | METH_KEYWORDS | METH_CLASS, - PyDoc_STR("[tz] -> new datetime with tz's local day and time.")}, + DATETIME_DATETIME_NOW_METHODDEF {"utcnow", (PyCFunction)datetime_utcnow, METH_NOARGS | METH_CLASS, @@ -5299,8 +5407,8 @@ PyInit__datetime(void) return NULL; /* module initialization */ - PyModule_AddIntConstant(m, "MINYEAR", MINYEAR); - PyModule_AddIntConstant(m, "MAXYEAR", MAXYEAR); + PyModule_AddIntMacro(m, MINYEAR); + PyModule_AddIntMacro(m, MAXYEAR); Py_INCREF(&PyDateTime_DateType); PyModule_AddObject(m, "date", (PyObject *) &PyDateTime_DateType); @@ -5344,12 +5452,12 @@ PyInit__datetime(void) assert(DI100Y == 25 * DI4Y - 1); assert(DI100Y == days_before_year(100+1)); - us_per_us = PyLong_FromLong(1); + one = PyLong_FromLong(1); us_per_ms = PyLong_FromLong(1000); us_per_second = PyLong_FromLong(1000000); us_per_minute = PyLong_FromLong(60000000); seconds_per_day = PyLong_FromLong(24 * 3600); - if (us_per_us == NULL || us_per_ms == NULL || us_per_second == NULL || + if (one == NULL || us_per_ms == NULL || us_per_second == NULL || us_per_minute == NULL || seconds_per_day == NULL) return NULL; |
