aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Modules/_datetimemodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_datetimemodule.c')
-rw-r--r--Modules/_datetimemodule.c185
1 files changed, 118 insertions, 67 deletions
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index fa231d92597..0ea225664fc 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
+[clinic start generated code]*/
+/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
+
/* 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;
}
@@ -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;
}
@@ -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;
@@ -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, "()");
}
@@ -4138,31 +4145,71 @@ 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(tz=None)\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_now(PyObject *cls, PyObject *args, PyObject *kw)
+datetime_datetime_now_impl(PyTypeObject *cls, PyObject *tz);
+
+static PyObject *
+datetime_datetime_now(PyTypeObject *cls, 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(cls, tz);
+
+exit:
+ return return_value;
+}
+
+static PyObject *
+datetime_datetime_now_impl(PyTypeObject *cls, PyObject *tz)
+/*[clinic end generated code: checksum=ca3d26a423b3f633b260c7622e303f0915a96f7c]*/
{
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 *)cls,
+ 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;
@@ -4199,7 +4246,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);
@@ -4421,6 +4467,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 +4531,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 +4796,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,7 +4809,6 @@ 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,
@@ -4873,9 +4919,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 +5042,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 +5350,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 +5395,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;