diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 520a51df879997..04e8be631dda93 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -1909,9 +1909,6 @@ def test_fromisocalendar_value_errors(self): (10000, 1, 1), (0, 1, 1), (9999999, 1, 1), - (2<<32, 1, 1), - (2019, 2<<32, 1), - (2019, 1, 2<<32), ] for isocal in isocals: diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index acdde83dc845a5..bafce17b1bcc1c 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -2876,13 +2876,18 @@ date_fromtimestamp(PyObject *cls, PyObject *obj) cls); } -/* Return new date from current time. - * We say this is equivalent to fromtimestamp(time.time()), and the - * only way to be sure of that is to *call* time.time(). That's not - * generally the same as calling C's time. - */ +/*[clinic input] +@classmethod +datetime.date.today + +Current date or datetime. + +Same as self.__class__.fromtimestamp(time.time()) +[clinic start generated code]*/ + static PyObject * -date_today(PyObject *cls, PyObject *dummy) +datetime_date_today_impl(PyTypeObject *type) +/*[clinic end generated code: output=d5474697df6b251c input=0dff9bfe3e2274b2]*/ { PyObject *time; PyObject *result; @@ -2897,8 +2902,12 @@ date_today(PyObject *cls, PyObject *dummy) * datetime.fromtimestamp. That's why we need all the accuracy * time.time() delivers; if someone were gonzo about optimization, * date.today() could get away with plain C time(). + * Besides, we claim that this method is equivalent to + * fromtimestamp(time.time()), and the only way to be of that is to *call* + * time.time(). That's not generally the same as calling C's time. */ - result = _PyObject_CallMethodIdOneArg(cls, &PyId_fromtimestamp, time); + result = _PyObject_CallMethodIdOneArg((PyObject *) type, + &PyId_fromtimestamp, time); Py_DECREF(time); return result; } @@ -2940,34 +2949,50 @@ datetime_date_fromtimestamp_capi(PyObject *cls, PyObject *args) return result; } -/* Return new date from proleptic Gregorian ordinal. Raises ValueError if - * the ordinal is out of range. - */ + +/*[clinic input] +@classmethod +datetime.date.fromordinal + + ordinal: int + / + +int -> date corresponding to a proleptic Gregorian ordinal. + +Raises ValueError if the ordinal is out of range. +[clinic start generated code]*/ + static PyObject * -date_fromordinal(PyObject *cls, PyObject *args) +datetime_date_fromordinal_impl(PyTypeObject *type, int ordinal) +/*[clinic end generated code: output=ea5cc69d86614a6b input=1d7158c082e677fd]*/ { PyObject *result = NULL; - int ordinal; - - if (PyArg_ParseTuple(args, "i:fromordinal", &ordinal)) { - int year; - int month; - int day; + int year; + int month; + int day; - if (ordinal < 1) - PyErr_SetString(PyExc_ValueError, "ordinal must be " - ">= 1"); - else { - ord_to_ymd(ordinal, &year, &month, &day); - result = new_date_subclass_ex(year, month, day, cls); - } + if (ordinal < 1) + PyErr_SetString(PyExc_ValueError, "ordinal must be >= 1"); + else { + ord_to_ymd(ordinal, &year, &month, &day); + result = new_date_subclass_ex(year, month, day, (PyObject *) type); } return result; } -/* Return the new date from a string as generated by date.isoformat() */ +/*[clinic input] +@classmethod +datetime.date.fromisoformat + + date_string as dtstr: object + / + +str -> Construct a date from the output of date.isoformat() +[clinic start generated code]*/ + static PyObject * -date_fromisoformat(PyObject *cls, PyObject *dtstr) +datetime_date_fromisoformat(PyTypeObject *type, PyObject *dtstr) +/*[clinic end generated code: output=0c55fa0175e3e94b input=6bebe824e582fd1e]*/ { assert(dtstr != NULL); @@ -2998,7 +3023,7 @@ date_fromisoformat(PyObject *cls, PyObject *dtstr) goto invalid_string_error; } - return new_date_subclass_ex(year, month, day, cls); + return new_date_subclass_ex(year, month, day, (PyObject *) type); invalid_string_error: PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr); @@ -3006,25 +3031,24 @@ date_fromisoformat(PyObject *cls, PyObject *dtstr) } -static PyObject * -date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) -{ - static char *keywords[] = { - "year", "week", "day", NULL - }; +/*[clinic input] +@classmethod +datetime.date.fromisocalendar - int year, week, day; - if (PyArg_ParseTupleAndKeywords(args, kw, "iii:fromisocalendar", - keywords, - &year, &week, &day) == 0) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - PyErr_Format(PyExc_ValueError, - "ISO calendar component out of range"); + year: int + week: int + day: int - } - return NULL; - } +int, int, int -> Construct a date from the ISO year, week number and weekday. + +This is the inverse of the date.isocalendar() function. +[clinic start generated code]*/ +static PyObject * +datetime_date_fromisocalendar_impl(PyTypeObject *type, int year, int week, + int day) +/*[clinic end generated code: output=7b26e15115d24df6 input=e3daae6e2b75f1be]*/ +{ // Year is bounded to 0 < year < 10000 because 9999-12-31 is (9999, 52, 5) if (year < MINYEAR || year > MAXYEAR) { PyErr_Format(PyExc_ValueError, "Year is out of range: %d", year); @@ -3062,7 +3086,7 @@ date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) ord_to_ymd(day_1 + day_offset, &year, &month, &day); - return new_date_subclass_ex(year, month, day, cls); + return new_date_subclass_ex(year, month, day, (PyObject *) type); } @@ -3485,25 +3509,10 @@ static PyMethodDef date_methods[] = { /* Class methods: */ DATETIME_DATE_FROMTIMESTAMP_METHODDEF - - {"fromordinal", (PyCFunction)date_fromordinal, METH_VARARGS | - METH_CLASS, - PyDoc_STR("int -> date corresponding to a proleptic Gregorian " - "ordinal.")}, - - {"fromisoformat", (PyCFunction)date_fromisoformat, METH_O | - METH_CLASS, - PyDoc_STR("str -> Construct a date from the output of date.isoformat()")}, - - {"fromisocalendar", (PyCFunction)(void(*)(void))date_fromisocalendar, - METH_VARARGS | METH_KEYWORDS | METH_CLASS, - PyDoc_STR("int, int, int -> Construct a date from the ISO year, week " - "number and weekday.\n\n" - "This is the inverse of the date.isocalendar() function")}, - - {"today", (PyCFunction)date_today, METH_NOARGS | METH_CLASS, - PyDoc_STR("Current date or datetime: same as " - "self.__class__.fromtimestamp(time.time()).")}, + DATETIME_DATE_FROMORDINAL_METHODDEF + DATETIME_DATE_FROMISOFORMAT_METHODDEF + DATETIME_DATE_FROMISOCALENDAR_METHODDEF + DATETIME_DATE_TODAY_METHODDEF /* Instance methods: */ diff --git a/Modules/clinic/_datetimemodule.c.h b/Modules/clinic/_datetimemodule.c.h index 7bd7c1986dc7bd..e0e0ccb22ba058 100644 --- a/Modules/clinic/_datetimemodule.c.h +++ b/Modules/clinic/_datetimemodule.c.h @@ -2,6 +2,26 @@ preserve [clinic start generated code]*/ +PyDoc_STRVAR(datetime_date_today__doc__, +"today($type, /)\n" +"--\n" +"\n" +"Current date or datetime.\n" +"\n" +"Same as self.__class__.fromtimestamp(time.time())"); + +#define DATETIME_DATE_TODAY_METHODDEF \ + {"today", (PyCFunction)datetime_date_today, METH_NOARGS|METH_CLASS, datetime_date_today__doc__}, + +static PyObject * +datetime_date_today_impl(PyTypeObject *type); + +static PyObject * +datetime_date_today(PyTypeObject *type, PyObject *Py_UNUSED(ignored)) +{ + return datetime_date_today_impl(type); +} + PyDoc_STRVAR(datetime_date_fromtimestamp__doc__, "fromtimestamp($type, timestamp, /)\n" "--\n" @@ -14,6 +34,93 @@ PyDoc_STRVAR(datetime_date_fromtimestamp__doc__, #define DATETIME_DATE_FROMTIMESTAMP_METHODDEF \ {"fromtimestamp", (PyCFunction)datetime_date_fromtimestamp, METH_O|METH_CLASS, datetime_date_fromtimestamp__doc__}, +PyDoc_STRVAR(datetime_date_fromordinal__doc__, +"fromordinal($type, ordinal, /)\n" +"--\n" +"\n" +"int -> date corresponding to a proleptic Gregorian ordinal.\n" +"\n" +"Raises ValueError if the ordinal is out of range."); + +#define DATETIME_DATE_FROMORDINAL_METHODDEF \ + {"fromordinal", (PyCFunction)datetime_date_fromordinal, METH_O|METH_CLASS, datetime_date_fromordinal__doc__}, + +static PyObject * +datetime_date_fromordinal_impl(PyTypeObject *type, int ordinal); + +static PyObject * +datetime_date_fromordinal(PyTypeObject *type, PyObject *arg) +{ + PyObject *return_value = NULL; + int ordinal; + + ordinal = _PyLong_AsInt(arg); + if (ordinal == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = datetime_date_fromordinal_impl(type, ordinal); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date_fromisoformat__doc__, +"fromisoformat($type, date_string, /)\n" +"--\n" +"\n" +"str -> Construct a date from the output of date.isoformat()"); + +#define DATETIME_DATE_FROMISOFORMAT_METHODDEF \ + {"fromisoformat", (PyCFunction)datetime_date_fromisoformat, METH_O|METH_CLASS, datetime_date_fromisoformat__doc__}, + +PyDoc_STRVAR(datetime_date_fromisocalendar__doc__, +"fromisocalendar($type, /, year, week, day)\n" +"--\n" +"\n" +"int, int, int -> Construct a date from the ISO year, week number and weekday.\n" +"\n" +"This is the inverse of the date.isocalendar() function."); + +#define DATETIME_DATE_FROMISOCALENDAR_METHODDEF \ + {"fromisocalendar", (PyCFunction)(void(*)(void))datetime_date_fromisocalendar, METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_date_fromisocalendar__doc__}, + +static PyObject * +datetime_date_fromisocalendar_impl(PyTypeObject *type, int year, int week, + int day); + +static PyObject * +datetime_date_fromisocalendar(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"year", "week", "day", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "fromisocalendar", 0}; + PyObject *argsbuf[3]; + int year; + int week; + int day; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); + if (!args) { + goto exit; + } + year = _PyLong_AsInt(args[0]); + if (year == -1 && PyErr_Occurred()) { + goto exit; + } + week = _PyLong_AsInt(args[1]); + if (week == -1 && PyErr_Occurred()) { + goto exit; + } + day = _PyLong_AsInt(args[2]); + if (day == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = datetime_date_fromisocalendar_impl(type, year, week, day); + +exit: + return return_value; +} + static PyObject * iso_calendar_date_new_impl(PyTypeObject *type, int year, int week, int weekday); @@ -94,4 +201,4 @@ datetime_datetime_now(PyTypeObject *type, PyObject *const *args, Py_ssize_t narg exit: return return_value; } -/*[clinic end generated code: output=f61310936e3d8091 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=45e5f93fa01f71fa input=a9049054013a1b77]*/