diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 16ed3215bc2c1a..7010f99c54da0a 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -2383,7 +2383,7 @@ locations where different offsets are used in different days of the year or where historical changes have been made to civil time. -.. class:: timezone(offset, name=None) +.. class:: timezone(offset[, name]) The *offset* argument must be specified as a :class:`timedelta` object representing the difference between the local time and UTC. It must diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index c461bc1786ddf4..5507bc6486dd68 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -891,7 +891,9 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(d_parameter_type)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(data)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(database)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(date)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(day)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(days)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(debug)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(decode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(decoder)); @@ -1000,6 +1002,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hi)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hook)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hour)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hours)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(id)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ident)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(identity_hint)); @@ -1095,8 +1098,10 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(metadata)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(method)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(microsecond)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(microseconds)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(milliseconds)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(minute)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(minutes)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(mod)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(mode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(module)); @@ -1207,6 +1212,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(scheduler)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(script)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(second)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(seconds)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(security_attributes)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(seek)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(seekable)); @@ -1271,9 +1277,12 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(text)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(threading)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(throw)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(time)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timeout)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timer)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(times)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timespec)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timestamp)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timetuple)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timeunit)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(top)); @@ -1305,6 +1314,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(wbits)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(week)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(weekday)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(weeks)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(which)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(who)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(withdata)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 72c2051bd97660..e5c27eb8b43f17 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -382,7 +382,9 @@ struct _Py_global_strings { STRUCT_FOR_ID(d_parameter_type) STRUCT_FOR_ID(data) STRUCT_FOR_ID(database) + STRUCT_FOR_ID(date) STRUCT_FOR_ID(day) + STRUCT_FOR_ID(days) STRUCT_FOR_ID(debug) STRUCT_FOR_ID(decode) STRUCT_FOR_ID(decoder) @@ -491,6 +493,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(hi) STRUCT_FOR_ID(hook) STRUCT_FOR_ID(hour) + STRUCT_FOR_ID(hours) STRUCT_FOR_ID(id) STRUCT_FOR_ID(ident) STRUCT_FOR_ID(identity_hint) @@ -586,8 +589,10 @@ struct _Py_global_strings { STRUCT_FOR_ID(metadata) STRUCT_FOR_ID(method) STRUCT_FOR_ID(microsecond) + STRUCT_FOR_ID(microseconds) STRUCT_FOR_ID(milliseconds) STRUCT_FOR_ID(minute) + STRUCT_FOR_ID(minutes) STRUCT_FOR_ID(mod) STRUCT_FOR_ID(mode) STRUCT_FOR_ID(module) @@ -698,6 +703,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(scheduler) STRUCT_FOR_ID(script) STRUCT_FOR_ID(second) + STRUCT_FOR_ID(seconds) STRUCT_FOR_ID(security_attributes) STRUCT_FOR_ID(seek) STRUCT_FOR_ID(seekable) @@ -762,9 +768,12 @@ struct _Py_global_strings { STRUCT_FOR_ID(text) STRUCT_FOR_ID(threading) STRUCT_FOR_ID(throw) + STRUCT_FOR_ID(time) STRUCT_FOR_ID(timeout) STRUCT_FOR_ID(timer) STRUCT_FOR_ID(times) + STRUCT_FOR_ID(timespec) + STRUCT_FOR_ID(timestamp) STRUCT_FOR_ID(timetuple) STRUCT_FOR_ID(timeunit) STRUCT_FOR_ID(top) @@ -796,6 +805,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(wbits) STRUCT_FOR_ID(week) STRUCT_FOR_ID(weekday) + STRUCT_FOR_ID(weeks) STRUCT_FOR_ID(which) STRUCT_FOR_ID(who) STRUCT_FOR_ID(withdata) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index d378fcae26cf35..3c9dcf885ce203 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -889,7 +889,9 @@ extern "C" { INIT_ID(d_parameter_type), \ INIT_ID(data), \ INIT_ID(database), \ + INIT_ID(date), \ INIT_ID(day), \ + INIT_ID(days), \ INIT_ID(debug), \ INIT_ID(decode), \ INIT_ID(decoder), \ @@ -998,6 +1000,7 @@ extern "C" { INIT_ID(hi), \ INIT_ID(hook), \ INIT_ID(hour), \ + INIT_ID(hours), \ INIT_ID(id), \ INIT_ID(ident), \ INIT_ID(identity_hint), \ @@ -1093,8 +1096,10 @@ extern "C" { INIT_ID(metadata), \ INIT_ID(method), \ INIT_ID(microsecond), \ + INIT_ID(microseconds), \ INIT_ID(milliseconds), \ INIT_ID(minute), \ + INIT_ID(minutes), \ INIT_ID(mod), \ INIT_ID(mode), \ INIT_ID(module), \ @@ -1205,6 +1210,7 @@ extern "C" { INIT_ID(scheduler), \ INIT_ID(script), \ INIT_ID(second), \ + INIT_ID(seconds), \ INIT_ID(security_attributes), \ INIT_ID(seek), \ INIT_ID(seekable), \ @@ -1269,9 +1275,12 @@ extern "C" { INIT_ID(text), \ INIT_ID(threading), \ INIT_ID(throw), \ + INIT_ID(time), \ INIT_ID(timeout), \ INIT_ID(timer), \ INIT_ID(times), \ + INIT_ID(timespec), \ + INIT_ID(timestamp), \ INIT_ID(timetuple), \ INIT_ID(timeunit), \ INIT_ID(top), \ @@ -1303,6 +1312,7 @@ extern "C" { INIT_ID(wbits), \ INIT_ID(week), \ INIT_ID(weekday), \ + INIT_ID(weeks), \ INIT_ID(which), \ INIT_ID(who), \ INIT_ID(withdata), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index e516211f6c6cbc..396842a13b5852 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1316,10 +1316,18 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(date); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(day); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(days); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(debug); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -1752,6 +1760,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(hours); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(id); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2132,6 +2144,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(microseconds); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(milliseconds); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2140,6 +2156,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(minutes); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(mod); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2580,6 +2600,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(seconds); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(security_attributes); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2836,6 +2860,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(time); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(timeout); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2848,6 +2876,14 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(timespec); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(timestamp); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(timetuple); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2972,6 +3008,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(weeks); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(which); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index bc35823f70144e..0955005df5ccee 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -1083,7 +1083,7 @@ def fromisocalendar(cls, year, week, day): @classmethod def strptime(cls, date_string, format): - """Parse a date string according to the given format (like time.strptime()).""" + """Parse string according to the given date format (like time.strptime()).""" import _strptime return _strptime._strptime_datetime_date(cls, date_string, format) @@ -1310,7 +1310,7 @@ def __reduce__(self): class tzinfo: - """Abstract base class for time zone info classes. + """Abstract base class for time zone info objects. Subclasses must override the tzname(), utcoffset() and dst() methods. """ @@ -1468,7 +1468,7 @@ def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold @classmethod def strptime(cls, date_string, format): - """string, format -> new time parsed from a string (like time.strptime()).""" + """Parse string according to the given time format (like time.strptime()).""" import _strptime return _strptime._strptime_datetime_time(cls, date_string, format) @@ -1776,7 +1776,7 @@ def __reduce__(self): class datetime(date): - """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]]) + """A combination of a date and a time. The year, month and day arguments are required. tzinfo may be None, or an instance of a tzinfo subclass. The remaining arguments may be ints. @@ -2209,7 +2209,7 @@ def __str__(self): @classmethod def strptime(cls, date_string, format): - 'string, format -> new datetime parsed from a string (like time.strptime()).' + """Parse string according to the given date and time format (like time.strptime()).""" import _strptime return _strptime._strptime_datetime_datetime(cls, date_string, format) @@ -2435,6 +2435,8 @@ def _isoweek1monday(year): class timezone(tzinfo): + """Fixed offset from UTC implementation of tzinfo.""" + __slots__ = '_offset', '_name' # Sentinel value to disallow None diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 93b3382b9c654e..8deb8be8a2bfc0 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -2147,14 +2147,20 @@ def test_fromisocalendar_value_errors(self): (10000, 1, 1), (0, 1, 1), (9999999, 1, 1), + ] + for isocal in isocals: + with self.subTest(isocal=isocal): + with self.assertRaises(ValueError): + self.theclass.fromisocalendar(*isocal) + + isocals = [ (2<<32, 1, 1), (2019, 2<<32, 1), (2019, 1, 2<<32), ] - for isocal in isocals: with self.subTest(isocal=isocal): - with self.assertRaises(ValueError): + with self.assertRaises((ValueError, OverflowError)): self.theclass.fromisocalendar(*isocal) def test_fromisocalendar_type_errors(self): @@ -2301,7 +2307,7 @@ def test_isoformat_timezone(self): dt = dt_base.replace(tzinfo=tzi) exp = exp_base + exp_tz with self.subTest(tzi=tzi): - assert dt.isoformat() == exp + self.assertEqual(dt.isoformat(), exp) def test_format(self): dt = self.theclass(2007, 9, 10, 4, 5, 1, 123) @@ -3349,7 +3355,7 @@ def test_fromisoformat_timezone(self): with self.subTest(tstr=dtstr): dt_rt = self.theclass.fromisoformat(dtstr) - assert dt == dt_rt, dt_rt + self.assertEqual(dt_rt, dt) def test_fromisoformat_separators(self): separators = [ @@ -3865,7 +3871,7 @@ def test_isoformat_timezone(self): t = t_base.replace(tzinfo=tzi) exp = exp_base + exp_tz with self.subTest(tzi=tzi): - assert t.isoformat() == exp + self.assertEqual(t.isoformat(), exp) def test_1653736(self): # verify it doesn't accept extra keyword arguments @@ -4350,7 +4356,7 @@ def utcoffset(self, t): elif x is d2: expected = -1 else: - assert y is d2 + self.assertIs(y, d2) expected = 1 self.assertEqual(got, expected) @@ -4678,7 +4684,7 @@ def test_fromisoformat_timezone(self): with self.subTest(tstr=tstr): t_rt = self.theclass.fromisoformat(tstr) - assert t == t_rt + self.assertEqual(t_rt, t) def test_fromisoformat_timespecs(self): time_bases = [ @@ -5515,7 +5521,7 @@ def utcoffset(self, t): elif x is d2: expected = timedelta(minutes=(11-59)-0) else: - assert y is d2 + self.assertIs(y, d2) expected = timedelta(minutes=0-(11-59)) self.assertEqual(got, expected) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 0ea029b977b3fc..74c779cc08aa88 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -5830,6 +5830,19 @@ def test_collections_abc_module_has_signatures(self): import collections.abc self._test_module_has_signatures(collections.abc) + def test_datetime_module_has_signatures(self): + import datetime + no_signature = {'tzinfo'} + unsupported_signature = {'timezone'} + methods_unsupported_signature = { + 'date': {'replace'}, + 'time': {'replace'}, + 'datetime': {'replace', 'combine'}, + } + self._test_module_has_signatures(datetime, + no_signature, unsupported_signature, + methods_unsupported_signature=methods_unsupported_signature) + def test_errno_module_has_signatures(self): import errno self._test_module_has_signatures(errno) diff --git a/Misc/NEWS.d/next/Library/2025-07-12-14-15-47.gh-issue-136571.muHmBv.rst b/Misc/NEWS.d/next/Library/2025-07-12-14-15-47.gh-issue-136571.muHmBv.rst new file mode 100644 index 00000000000000..37f535f564883c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-12-14-15-47.gh-issue-136571.muHmBv.rst @@ -0,0 +1,2 @@ +:meth:`datetime.date.fromisocalendar` can now raise OverflowError for out of +range arguments. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 7a6426593d021f..b4e9779ca411e7 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -335,8 +335,10 @@ class datetime.datetime "PyDateTime_DateTime *" "get_datetime_state()->datetime_ class datetime.date "PyDateTime_Date *" "get_datetime_state()->date_type" class datetime.time "PyDateTime_Time *" "get_datetime_state()->time_type" class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "get_datetime_state()->isocalendar_date_type" +class datetime.timedelta "PyDateTime_Delta *" "&PyDateTime_DeltaType" +class datetime.timezone "PyDateTime_TimeZone *" "&PyDateTime_TimeZoneType" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c8f3d834a860d50a]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c54b9adf60082f0d]*/ #include "clinic/_datetimemodule.c.h" @@ -1175,19 +1177,18 @@ new_datetime_ex(int, int, int, int, int, int, int, PyObject *, PyTypeObject *); /* Create date instance with no range checking, or call subclass constructor */ static PyObject * -new_date_subclass_ex(int year, int month, int day, PyObject *cls) +new_date_subclass_ex(int year, int month, int day, PyTypeObject *cls) { PyObject *result; // We have "fast path" constructors for two subclasses: date and datetime - if ((PyTypeObject *)cls == DATE_TYPE(NO_STATE)) { - result = new_date_ex(year, month, day, (PyTypeObject *)cls); + if (cls == DATE_TYPE(NO_STATE)) { + result = new_date_ex(year, month, day, cls); } - else if ((PyTypeObject *)cls == DATETIME_TYPE(NO_STATE)) { - result = new_datetime_ex(year, month, day, 0, 0, 0, 0, Py_None, - (PyTypeObject *)cls); + else if (cls == DATETIME_TYPE(NO_STATE)) { + result = new_datetime_ex(year, month, day, 0, 0, 0, 0, Py_None, cls); } else { - result = PyObject_CallFunction(cls, "iii", year, month, day); + result = PyObject_CallFunction((PyObject *)cls, "iii", year, month, day); } return result; @@ -1239,7 +1240,7 @@ new_datetime_ex(int year, int month, int day, int hour, int minute, new_datetime_ex2(y, m, d, hh, mm, ss, us, tzinfo, fold, DATETIME_TYPE(NO_STATE)) static PyObject * -call_subclass_fold(PyObject *cls, int fold, const char *format, ...) +call_subclass_fold(PyTypeObject *cls, int fold, const char *format, ...) { PyObject *kwargs = NULL, *res = NULL; va_list va; @@ -1265,7 +1266,7 @@ call_subclass_fold(PyObject *cls, int fold, const char *format, ...) goto Done; } } - res = PyObject_Call(cls, args, kwargs); + res = PyObject_Call((PyObject *)cls, args, kwargs); Done: Py_DECREF(args); Py_XDECREF(kwargs); @@ -1275,10 +1276,10 @@ call_subclass_fold(PyObject *cls, int fold, const char *format, ...) static PyObject * new_datetime_subclass_fold_ex(int year, int month, int day, int hour, int minute, int second, int usecond, PyObject *tzinfo, - int fold, PyObject *cls) + int fold, PyTypeObject *cls) { PyObject* dt; - if ((PyTypeObject*)cls == DATETIME_TYPE(NO_STATE)) { + if (cls == DATETIME_TYPE(NO_STATE)) { // Use the fast path constructor dt = new_datetime(year, month, day, hour, minute, second, usecond, tzinfo, fold); @@ -1295,7 +1296,7 @@ new_datetime_subclass_fold_ex(int year, int month, int day, int hour, int minute static PyObject * new_datetime_subclass_ex(int year, int month, int day, int hour, int minute, int second, int usecond, PyObject *tzinfo, - PyObject *cls) { + PyTypeObject *cls) { return new_datetime_subclass_fold_ex(year, month, day, hour, minute, second, usecond, tzinfo, 0, cls); @@ -1344,10 +1345,10 @@ new_time_ex(int hour, int minute, int second, int usecond, static PyObject * new_time_subclass_fold_ex(int hour, int minute, int second, int usecond, - PyObject *tzinfo, int fold, PyObject *cls) + PyObject *tzinfo, int fold, PyTypeObject *cls) { PyObject *t; - if ((PyTypeObject*)cls == TIME_TYPE(NO_STATE)) { + if (cls == TIME_TYPE(NO_STATE)) { // Use the fast path constructor t = new_time(hour, minute, second, usecond, tzinfo, fold); } @@ -2772,38 +2773,39 @@ accum(const char* tag, PyObject *sofar, PyObject *num, PyObject *factor, return NULL; } +/*[clinic input] +@classmethod +datetime.timedelta.__new__ as delta_new + + days: object(c_default="NULL") = 0 + seconds: object(c_default="NULL") = 0 + microseconds: object(c_default="NULL") = 0 + milliseconds: object(c_default="NULL") = 0 + minutes: object(c_default="NULL") = 0 + hours: object(c_default="NULL") = 0 + weeks: object(c_default="NULL") = 0 + +Difference between two datetime values. + +All arguments are optional and default to 0. +Arguments may be integers or floats, and may be positive or negative. +[clinic start generated code]*/ + static PyObject * -delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) +delta_new_impl(PyTypeObject *type, PyObject *days, PyObject *seconds, + PyObject *microseconds, PyObject *milliseconds, + PyObject *minutes, PyObject *hours, PyObject *weeks) +/*[clinic end generated code: output=61d7e02a92a97700 input=e8cd54819295d34b]*/ { PyObject *self = NULL; PyObject *current_mod = NULL; datetime_state *st = GET_CURRENT_STATE(current_mod); - /* Argument objects. */ - PyObject *day = NULL; - PyObject *second = NULL; - PyObject *us = NULL; - PyObject *ms = NULL; - PyObject *minute = NULL; - PyObject *hour = NULL; - PyObject *week = NULL; - PyObject *x = NULL; /* running sum of microseconds */ PyObject *y = NULL; /* temp sum of microseconds */ double leftover_us = 0.0; - static char *keywords[] = { - "days", "seconds", "microseconds", "milliseconds", - "minutes", "hours", "weeks", NULL - }; - - if (PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOO:__new__", - keywords, - &day, &second, &us, - &ms, &minute, &hour, &week) == 0) - goto Done; - x = PyLong_FromLong(0); if (x == NULL) goto Done; @@ -2814,32 +2816,32 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) if (x == NULL) \ goto Done - if (us) { - y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us); + if (microseconds) { + y = accum("microseconds", x, microseconds, _PyLong_GetOne(), &leftover_us); CLEANUP; } - if (ms) { - y = accum("milliseconds", x, ms, CONST_US_PER_MS(st), &leftover_us); + if (milliseconds) { + y = accum("milliseconds", x, milliseconds, CONST_US_PER_MS(st), &leftover_us); CLEANUP; } - if (second) { - y = accum("seconds", x, second, CONST_US_PER_SECOND(st), &leftover_us); + if (seconds) { + y = accum("seconds", x, seconds, CONST_US_PER_SECOND(st), &leftover_us); CLEANUP; } - if (minute) { - y = accum("minutes", x, minute, CONST_US_PER_MINUTE(st), &leftover_us); + if (minutes) { + y = accum("minutes", x, minutes, CONST_US_PER_MINUTE(st), &leftover_us); CLEANUP; } - if (hour) { - y = accum("hours", x, hour, CONST_US_PER_HOUR(st), &leftover_us); + if (hours) { + y = accum("hours", x, hours, CONST_US_PER_HOUR(st), &leftover_us); CLEANUP; } - if (day) { - y = accum("days", x, day, CONST_US_PER_DAY(st), &leftover_us); + if (days) { + y = accum("days", x, days, CONST_US_PER_DAY(st), &leftover_us); CLEANUP; } - if (week) { - y = accum("weeks", x, week, CONST_US_PER_WEEK(st), &leftover_us); + if (weeks) { + y = accum("weeks", x, weeks, CONST_US_PER_WEEK(st), &leftover_us); CLEANUP; } if (leftover_us) { @@ -3038,13 +3040,6 @@ static PyMethodDef delta_methods[] = { {NULL, NULL}, }; -static const char delta_doc[] = -PyDoc_STR("Difference between two datetime values.\n\n" - "timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, " - "minutes=0, hours=0, weeks=0)\n\n" - "All arguments are optional and default to 0.\n" - "Arguments may be integers or floats, and may be positive or negative."); - static PyNumberMethods delta_as_number = { delta_add, /* nb_add */ delta_subtract, /* nb_subtract */ @@ -3102,7 +3097,7 @@ static PyTypeObject PyDateTime_DeltaType = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - delta_doc, /* tp_doc */ + delta_new__doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ delta_richcompare, /* tp_richcompare */ @@ -3178,8 +3173,6 @@ static PyGetSetDef date_getset[] = { /* Constructors. */ -static char *date_kws[] = {"year", "month", "day", NULL}; - static PyObject * date_from_pickle(PyTypeObject *type, PyObject *state) { @@ -3197,11 +3190,6 @@ date_from_pickle(PyTypeObject *type, PyObject *state) static PyObject * date_new(PyTypeObject *type, PyObject *args, PyObject *kw) { - PyObject *self = NULL; - int year; - int month; - int day; - /* Check for invocation from pickle with __getstate__ state */ if (PyTuple_GET_SIZE(args) == 1) { PyObject *state = PyTuple_GET_ITEM(args, 0); @@ -3227,22 +3215,36 @@ date_new(PyTypeObject *type, PyObject *args, PyObject *kw) } return NULL; } - self = date_from_pickle(type, state); + PyObject *self = date_from_pickle(type, state); Py_DECREF(state); return self; } } } - if (PyArg_ParseTupleAndKeywords(args, kw, "iii", date_kws, - &year, &month, &day)) { - self = new_date_ex(year, month, day, type); - } - return self; + return datetime_date(type, args, kw); +} + +/*[clinic input] +@classmethod +datetime.date.__new__ + + year: int + month: int + day: int + +Concrete date type. +[clinic start generated code]*/ + +static PyObject * +datetime_date_impl(PyTypeObject *type, int year, int month, int day) +/*[clinic end generated code: output=6654caa3dea7d518 input=fd1bac0658690455]*/ +{ + return new_date_ex(year, month, day, type); } static PyObject * -date_fromtimestamp(PyObject *cls, PyObject *obj) +date_fromtimestamp(PyTypeObject *cls, PyObject *obj) { struct tm tm; time_t t; @@ -3264,8 +3266,18 @@ date_fromtimestamp(PyObject *cls, PyObject *obj) * 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. + +Equivalent to fromtimestamp(time.time()). +[clinic start generated code]*/ + static PyObject * -date_today(PyObject *cls, PyObject *Py_UNUSED(dummy)) +datetime_date_today_impl(PyTypeObject *type) +/*[clinic end generated code: output=d5474697df6b251c input=21688afa289c0a06]*/ { PyObject *time; PyObject *result; @@ -3279,7 +3291,7 @@ date_today(PyObject *cls, PyObject *Py_UNUSED(dummy)) * time.time() delivers; if someone were gonzo about optimization, * date.today() could get away with plain C time(). */ - result = PyObject_CallMethodOneArg(cls, &_Py_ID(fromtimestamp), time); + result = PyObject_CallMethodOneArg((PyObject*)type, &_Py_ID(fromtimestamp), time); Py_DECREF(time); return result; } @@ -3301,7 +3313,7 @@ static PyObject * datetime_date_fromtimestamp_impl(PyTypeObject *type, PyObject *timestamp) /*[clinic end generated code: output=59def4e32c028fb6 input=eabb3fe7f40491fe]*/ { - return date_fromtimestamp((PyObject *) type, timestamp); + return date_fromtimestamp(type, timestamp); } /* bpo-36025: This is a wrapper for API compatibility with the public C API, @@ -3315,52 +3327,58 @@ datetime_date_fromtimestamp_capi(PyObject *cls, PyObject *args) PyObject *result = NULL; if (PyArg_UnpackTuple(args, "fromtimestamp", 1, 1, ×tamp)) { - result = date_fromtimestamp(cls, timestamp); + result = date_fromtimestamp((PyTypeObject *)cls, timestamp); } return result; } -/* Return new date from proleptic Gregorian ordinal. Raises ValueError if - * the ordinal is out of range. - */ -static PyObject * -date_fromordinal(PyObject *cls, PyObject *args) -{ - PyObject *result = NULL; - int ordinal; +/*[clinic input] +@classmethod +datetime.date.fromordinal - if (PyArg_ParseTuple(args, "i:fromordinal", &ordinal)) { - int year; - int month; - int day; + ordinal: int + / - 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); - } - } - return result; -} +Construct a date from a proleptic Gregorian ordinal. + +January 1 of year 1 is day 1. Only the year, month and day are +non-zero in the result. +[clinic start generated code]*/ -/* Return the new date from a string as generated by date.isoformat() */ static PyObject * -date_fromisoformat(PyObject *cls, PyObject *dtstr) +datetime_date_fromordinal_impl(PyTypeObject *type, int ordinal) +/*[clinic end generated code: output=ea5cc69d86614a6b input=a3a4eedf582f145e]*/ { - assert(dtstr != NULL); + int year; + int month; + int day; - if (!PyUnicode_Check(dtstr)) { - PyErr_SetString(PyExc_TypeError, - "fromisoformat: argument must be str"); + if (ordinal < 1) { + PyErr_SetString(PyExc_ValueError, "ordinal must be >= 1"); return NULL; } + ord_to_ymd(ordinal, &year, &month, &day); + return new_date_subclass_ex(year, month, day, type); +} + +/*[clinic input] +@classmethod +datetime.date.fromisoformat + string: unicode + / + +Construct a date from a string in ISO 8601 format. +[clinic start generated code]*/ + +static PyObject * +datetime_date_fromisoformat_impl(PyTypeObject *type, PyObject *string) +/*[clinic end generated code: output=8b9f9324904fca02 input=73c64216c10bcc8e]*/ +{ Py_ssize_t len; - const char *dt_ptr = PyUnicode_AsUTF8AndSize(dtstr, &len); + const char *dt_ptr = PyUnicode_AsUTF8AndSize(string, &len); if (dt_ptr == NULL) { goto invalid_string_error; } @@ -3379,33 +3397,32 @@ 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, type); invalid_string_error: - PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr); + PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", string); return NULL; } -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; - } +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=fbb05b53d6fb51d8]*/ +{ int month; int rv = iso_to_ymd(year, week, day, &year, &month, &day); @@ -3426,26 +3443,34 @@ date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) return NULL; } - return new_date_subclass_ex(year, month, day, cls); + return new_date_subclass_ex(year, month, day, type); } -/* Return new date from _strptime.strptime_datetime_date(). */ +/*[clinic input] +@classmethod +datetime.date.strptime + + string: unicode + format: unicode + / + +Parse string according to the given date format (like time.strptime()). +[clinic start generated code]*/ + static PyObject * -date_strptime(PyObject *cls, PyObject *args) +datetime_date_strptime_impl(PyTypeObject *type, PyObject *string, + PyObject *format) +/*[clinic end generated code: output=454d473bee2d5161 input=001904ab34f594a1]*/ { - PyObject *string, *format, *result; - - if (!PyArg_ParseTuple(args, "UU:strptime", &string, &format)) { - return NULL; - } + PyObject *result; PyObject *module = PyImport_Import(&_Py_ID(_strptime)); if (module == NULL) { return NULL; } result = PyObject_CallMethodObjArgs(module, - &_Py_ID(_strptime_datetime_date), cls, - string, format, NULL); + &_Py_ID(_strptime_datetime_date), + (PyObject *)type, string, format, NULL); Py_DECREF(module); return result; } @@ -3469,8 +3494,7 @@ add_date_timedelta(PyDateTime_Date *date, PyDateTime_Delta *delta, int negate) int day = GET_DAY(date) + (negate ? -deltadays : deltadays); if (normalize_date(&year, &month, &day) >= 0) - result = new_date_subclass_ex(year, month, day, - (PyObject* )Py_TYPE(date)); + result = new_date_subclass_ex(year, month, day, Py_TYPE(date)); return result; } @@ -3562,20 +3586,26 @@ date_ctime(PyObject *self, PyObject *Py_UNUSED(dummy)) return format_ctime(self, 0, 0, 0); } +/*[clinic input] +datetime.date.strftime + + self: self(type="PyObject *") + format: unicode + +Format using strftime(). + +Example: "%d/%m/%Y, %H:%M:%S". +[clinic start generated code]*/ + static PyObject * -date_strftime(PyObject *self, PyObject *args, PyObject *kw) +datetime_date_strftime_impl(PyObject *self, PyObject *format) +/*[clinic end generated code: output=6529b70095e16778 input=72af55077e606ed8]*/ { /* This method can be inherited, and needs to call the * timetuple() method appropriate to self's class. */ PyObject *result; PyObject *tuple; - PyObject *format; - static char *keywords[] = {"format", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kw, "U:strftime", keywords, - &format)) - return NULL; tuple = PyObject_CallMethodNoArgs(self, &_Py_ID(timetuple)); if (tuple == NULL) @@ -3585,14 +3615,20 @@ date_strftime(PyObject *self, PyObject *args, PyObject *kw) return result; } -static PyObject * -date_format(PyObject *self, PyObject *args) -{ - PyObject *format; +/*[clinic input] +datetime.date.__format__ - if (!PyArg_ParseTuple(args, "U:__format__", &format)) - return NULL; + self: self(type="PyObject *") + format: unicode + / + +Formats self with strftime. +[clinic start generated code]*/ +static PyObject * +datetime_date___format___impl(PyObject *self, PyObject *format) +/*[clinic end generated code: output=efa0223d000a93b7 input=e417a7c84e1abaf9]*/ +{ /* if the format is zero length, return str(self) */ if (PyUnicode_GetLength(format) == 0) return PyObject_Str(self); @@ -3838,7 +3874,7 @@ datetime_date_replace_impl(PyDateTime_Date *self, int year, int month, int day) /*[clinic end generated code: output=2a9430d1e6318aeb input=0d1f02685b3e90f6]*/ { - return new_date_subclass_ex(year, month, day, (PyObject *)Py_TYPE(self)); + return new_date_subclass_ex(year, month, day, Py_TYPE(self)); } static Py_hash_t @@ -3899,38 +3935,19 @@ static PyMethodDef date_methods[] = { /* Class methods: */ DATETIME_DATE_FROMTIMESTAMP_METHODDEF - - {"fromordinal", date_fromordinal, METH_VARARGS | METH_CLASS, - PyDoc_STR("int -> date corresponding to a proleptic Gregorian " - "ordinal.")}, - - {"fromisoformat", date_fromisoformat, METH_O | METH_CLASS, - PyDoc_STR("str -> Construct a date from a string in ISO 8601 format.")}, - - {"fromisocalendar", _PyCFunction_CAST(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")}, - - {"strptime", date_strptime, METH_VARARGS | METH_CLASS, - PyDoc_STR("string, format -> new date parsed from a string " - "(like time.strptime()).")}, - - {"today", 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_STRPTIME_METHODDEF + DATETIME_DATE_TODAY_METHODDEF /* Instance methods: */ {"ctime", date_ctime, METH_NOARGS, PyDoc_STR("Return ctime() style string.")}, - {"strftime", _PyCFunction_CAST(date_strftime), METH_VARARGS | METH_KEYWORDS, - PyDoc_STR("format -> strftime() style string.")}, - - {"__format__", date_format, METH_VARARGS, - PyDoc_STR("Formats self with strftime.")}, + DATETIME_DATE_STRFTIME_METHODDEF + DATETIME_DATE___FORMAT___METHODDEF {"timetuple", date_timetuple, METH_NOARGS, PyDoc_STR("Return time tuple, compatible with time.localtime().")}, @@ -3965,9 +3982,6 @@ static PyMethodDef date_methods[] = { {NULL, NULL} }; -static const char date_doc[] = -PyDoc_STR("date(year, month, day) --> date object"); - static PyNumberMethods date_as_number = { date_add, /* nb_add */ date_subtract, /* nb_subtract */ @@ -4002,7 +4016,7 @@ static PyTypeObject PyDateTime_DateType = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - date_doc, /* tp_doc */ + datetime_date__doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ date_richcompare, /* tp_richcompare */ @@ -4205,7 +4219,8 @@ static PyMethodDef tzinfo_methods[] = { }; static const char tzinfo_doc[] = -PyDoc_STR("Abstract base class for time zone info objects."); +PyDoc_STR("Abstract base class for time zone info objects.\n\n" + "Subclasses must override the tzname(), utcoffset() and dst() methods."); static PyTypeObject PyDateTime_TZInfoType = { PyVarObject_HEAD_INIT(NULL, 0) @@ -4249,18 +4264,21 @@ static PyTypeObject PyDateTime_TZInfoType = { 0, /* tp_free */ }; -static char *timezone_kws[] = {"offset", "name", NULL}; +/*[clinic input] +@classmethod +datetime.timezone.__new__ as timezone_new + + offset: object(subclass_of="DELTA_TYPE(NO_STATE)") + name: unicode = NULL + +Fixed offset from UTC implementation of tzinfo. +[clinic start generated code]*/ static PyObject * -timezone_new(PyTypeObject *type, PyObject *args, PyObject *kw) +timezone_new_impl(PyTypeObject *type, PyObject *offset, PyObject *name) +/*[clinic end generated code: output=41a2dda500424187 input=d51255afe60382cd]*/ { - PyObject *offset; - PyObject *name = NULL; - if (PyArg_ParseTupleAndKeywords(args, kw, "O!|U:timezone", timezone_kws, - DELTA_TYPE(NO_STATE), &offset, &name)) - return new_timezone(offset, name); - - return NULL; + return new_timezone(offset, name); } static void @@ -4448,9 +4466,6 @@ static PyMethodDef timezone_methods[] = { {NULL, NULL} }; -static const char timezone_doc[] = -PyDoc_STR("Fixed offset from UTC implementation of tzinfo."); - static PyTypeObject PyDateTime_TimeZoneType = { PyVarObject_HEAD_INIT(NULL, 0) "datetime.timezone", /* tp_name */ @@ -4472,7 +4487,7 @@ static PyTypeObject PyDateTime_TimeZoneType = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ - timezone_doc, /* tp_doc */ + timezone_new__doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ timezone_richcompare, /* tp_richcompare */ @@ -4574,9 +4589,6 @@ static PyGetSetDef time_getset[] = { * Constructors. */ -static char *time_kws[] = {"hour", "minute", "second", "microsecond", - "tzinfo", "fold", NULL}; - static PyObject * time_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo) { @@ -4612,17 +4624,10 @@ time_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo) static PyObject * time_new(PyTypeObject *type, PyObject *args, PyObject *kw) { - PyObject *self = NULL; - int hour = 0; - int minute = 0; - int second = 0; - int usecond = 0; - PyObject *tzinfo = Py_None; - int fold = 0; - /* Check for invocation from pickle with __getstate__ state */ if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2) { PyObject *state = PyTuple_GET_ITEM(args, 0); + PyObject *tzinfo = Py_None; if (PyTuple_GET_SIZE(args) == 2) { tzinfo = PyTuple_GET_ITEM(args, 1); } @@ -4648,40 +4653,67 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw) } return NULL; } - self = time_from_pickle(type, state, tzinfo); + PyObject *self = time_from_pickle(type, state, tzinfo); Py_DECREF(state); return self; } } - tzinfo = Py_None; } - if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i", time_kws, - &hour, &minute, &second, &usecond, - &tzinfo, &fold)) { - self = new_time_ex2(hour, minute, second, usecond, tzinfo, fold, - type); - } - return self; + return datetime_time(type, args, kw); } -/* Return new time from _strptime.strptime_datetime_time(). */ +/*[clinic input] +@classmethod +datetime.time.__new__ + + hour: int = 0 + minute: int = 0 + second: int = 0 + microsecond: int = 0 + tzinfo: object = None + * + fold: int = 0 + +Time with time zone. + +All arguments are optional. tzinfo may be None, or an instance of +a tzinfo subclass. The remaining arguments may be ints. +[clinic start generated code]*/ + static PyObject * -time_strptime(PyObject *cls, PyObject *args) +datetime_time_impl(PyTypeObject *type, int hour, int minute, int second, + int microsecond, PyObject *tzinfo, int fold) +/*[clinic end generated code: output=f06bb4315225e7f6 input=0148df5e8138fe7b]*/ { - PyObject *string, *format, *result; + return new_time_ex2(hour, minute, second, microsecond, tzinfo, fold, type); +} - if (!PyArg_ParseTuple(args, "UU:strptime", &string, &format)) { - return NULL; - } +/*[clinic input] +@classmethod +datetime.time.strptime + + string: unicode + format: unicode + / + +Parse string according to the given time format (like time.strptime()). +[clinic start generated code]*/ + +static PyObject * +datetime_time_strptime_impl(PyTypeObject *type, PyObject *string, + PyObject *format) +/*[clinic end generated code: output=ae05a9bc0241d3bf input=6d0f263a5f94d78d]*/ +{ + PyObject *result; PyObject *module = PyImport_Import(&_Py_ID(_strptime)); if (module == NULL) { return NULL; } result = PyObject_CallMethodObjArgs(module, - &_Py_ID(_strptime_datetime_time), cls, - string, format, NULL); + &_Py_ID(_strptime_datetime_time), + (PyObject *)type, string, format, NULL); Py_DECREF(module); return result; } @@ -4760,17 +4792,30 @@ time_str(PyObject *op) return PyObject_CallMethodNoArgs(op, &_Py_ID(isoformat)); } +/*[clinic input] +datetime.time.isoformat + + timespec: str(c_default="NULL") = 'auto' + +Return the time formatted according to ISO. + +The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional +part is omitted if self.microsecond == 0. + +The optional argument timespec specifies the number of additional +terms of the time to include. Valid options are 'auto', 'hours', +'minutes', 'seconds', 'milliseconds' and 'microseconds'. +[clinic start generated code]*/ + static PyObject * -time_isoformat(PyObject *op, PyObject *args, PyObject *kw) +datetime_time_isoformat_impl(PyDateTime_Time *self, const char *timespec) +/*[clinic end generated code: output=2bcc7cab65c35545 input=afbbbd953d10ad07]*/ { char buf[100]; - const char *timespec = NULL; - static char *keywords[] = {"timespec", NULL}; - PyDateTime_Time *self = PyTime_CAST(op); PyObject *result; int us = TIME_GET_MICROSECOND(self); - static const char *specs[][2] = { + static const char * const specs[][2] = { {"hours", "%02d"}, {"minutes", "%02d:%02d"}, {"seconds", "%02d:%02d:%02d"}, @@ -4779,9 +4824,6 @@ time_isoformat(PyObject *op, PyObject *args, PyObject *kw) }; size_t given_spec; - if (!PyArg_ParseTupleAndKeywords(args, kw, "|s:isoformat", keywords, ×pec)) - return NULL; - if (timespec == NULL || strcmp(timespec, "auto") == 0) { if (us == 0) { /* seconds */ @@ -4827,18 +4869,22 @@ time_isoformat(PyObject *op, PyObject *args, PyObject *kw) return result; } +/*[clinic input] +datetime.time.strftime + + format: unicode + +Format using strftime(). + +The date part of the timestamp passed to underlying strftime should not be used. +[clinic start generated code]*/ + static PyObject * -time_strftime(PyObject *op, PyObject *args, PyObject *kw) +datetime_time_strftime_impl(PyDateTime_Time *self, PyObject *format) +/*[clinic end generated code: output=10f65af20e2a78c7 input=7dd9df1acbf37b50]*/ { PyObject *result; PyObject *tuple; - PyObject *format; - static char *keywords[] = {"format", NULL}; - PyDateTime_Time *self = PyTime_CAST(op); - - if (! PyArg_ParseTupleAndKeywords(args, kw, "U:strftime", keywords, - &format)) - return NULL; /* Python's strftime does insane things with the year part of the * timetuple. The year is forced to (the otherwise nonsensical) @@ -4859,6 +4905,27 @@ time_strftime(PyObject *op, PyObject *args, PyObject *kw) return result; } +/*[clinic input] +datetime.time.__format__ + + self: self(type="PyObject *") + format: unicode + / + +Formats self with strftime. +[clinic start generated code]*/ + +static PyObject * +datetime_time___format___impl(PyObject *self, PyObject *format) +/*[clinic end generated code: output=4646451f7a5d2156 input=6a858ae787d20230]*/ +{ + /* if the format is zero length, return str(self) */ + if (PyUnicode_GetLength(format) == 0) + return PyObject_Str(self); + + return PyObject_CallMethodOneArg(self, &_Py_ID(strftime), format); +} + /* * Miscellaneous methods. */ @@ -5011,20 +5078,25 @@ datetime_time_replace_impl(PyDateTime_Time *self, int hour, int minute, /*[clinic end generated code: output=0b89a44c299e4f80 input=abf23656e8df4e97]*/ { return new_time_subclass_fold_ex(hour, minute, second, microsecond, tzinfo, - fold, (PyObject *)Py_TYPE(self)); + fold, Py_TYPE(self)); } -static PyObject * -time_fromisoformat(PyObject *cls, PyObject *tstr) { - assert(tstr != NULL); +/*[clinic input] +@classmethod +datetime.time.fromisoformat - if (!PyUnicode_Check(tstr)) { - PyErr_SetString(PyExc_TypeError, "fromisoformat: argument must be str"); - return NULL; - } + string: unicode + / + +Construct a time from a string in ISO 8601 format. +[clinic start generated code]*/ +static PyObject * +datetime_time_fromisoformat_impl(PyTypeObject *type, PyObject *string) +/*[clinic end generated code: output=97c57e896e7f2535 input=bdb4b8abea9cd688]*/ +{ Py_ssize_t len; - const char *p = PyUnicode_AsUTF8AndSize(tstr, &len); + const char *p = PyUnicode_AsUTF8AndSize(string, &len); if (p == NULL) { goto invalid_string_error; @@ -5067,10 +5139,10 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) { } PyObject *t; - if ( (PyTypeObject *)cls == TIME_TYPE(NO_STATE)) { + if (type == TIME_TYPE(NO_STATE)) { t = new_time(hour, minute, second, microsecond, tzinfo, 0); } else { - t = PyObject_CallFunction(cls, "iiiiO", + t = PyObject_CallFunction((PyObject *)type, "iiiiO", hour, minute, second, microsecond, tzinfo); } @@ -5082,7 +5154,7 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) { return NULL; invalid_string_error: - PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", tstr); + PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", string); return NULL; error: @@ -5118,21 +5190,28 @@ time_getstate(PyDateTime_Time *self, int proto) return result; } +/*[clinic input] +datetime.time.__reduce_ex__ + + proto: int + / +[clinic start generated code]*/ + static PyObject * -time_reduce_ex(PyObject *op, PyObject *args) +datetime_time___reduce_ex___impl(PyDateTime_Time *self, int proto) +/*[clinic end generated code: output=ccfab65f5c320c1b input=4cd06bb3ac3657bb]*/ { - int proto; - if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto)) - return NULL; - - PyDateTime_Time *self = PyTime_CAST(op); return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, proto)); } +/*[clinic input] +datetime.time.__reduce__ +[clinic start generated code]*/ + static PyObject * -time_reduce(PyObject *op, PyObject *Py_UNUSED(dummy)) +datetime_time___reduce___impl(PyDateTime_Time *self) +/*[clinic end generated code: output=9a2fcc87e64ce300 input=0fb8dd14d275857f]*/ { - PyDateTime_Time *self = PyTime_CAST(op); return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, 2)); } @@ -5140,26 +5219,14 @@ static PyMethodDef time_methods[] = { /* Class method: */ - {"strptime", time_strptime, - METH_VARARGS | METH_CLASS, - PyDoc_STR("string, format -> new time parsed from a string " - "(like time.strptime()).")}, + DATETIME_TIME_FROMISOFORMAT_METHODDEF + DATETIME_TIME_STRPTIME_METHODDEF /* Instance methods: */ - {"isoformat", _PyCFunction_CAST(time_isoformat), METH_VARARGS | METH_KEYWORDS, - PyDoc_STR("Return string in ISO 8601 format, [HH[:MM[:SS[.mmm[uuu]]]]]" - "[+HH:MM].\n\n" - "The optional argument timespec specifies the number " - "of additional terms\nof the time to include. Valid " - "options are 'auto', 'hours', 'minutes',\n'seconds', " - "'milliseconds' and 'microseconds'.\n")}, - - {"strftime", _PyCFunction_CAST(time_strftime), METH_VARARGS | METH_KEYWORDS, - PyDoc_STR("format -> strftime() style string.")}, - - {"__format__", date_format, METH_VARARGS, - PyDoc_STR("Formats self with strftime.")}, + DATETIME_TIME_ISOFORMAT_METHODDEF + DATETIME_TIME_STRFTIME_METHODDEF + DATETIME_TIME___FORMAT___METHODDEF {"utcoffset", time_utcoffset, METH_NOARGS, PyDoc_STR("Return self.tzinfo.utcoffset(self).")}, @@ -5175,24 +5242,12 @@ static PyMethodDef time_methods[] = { {"__replace__", _PyCFunction_CAST(datetime_time_replace), METH_FASTCALL | METH_KEYWORDS, PyDoc_STR("__replace__($self, /, **changes)\n--\n\nThe same as replace().")}, - {"fromisoformat", time_fromisoformat, METH_O | METH_CLASS, - PyDoc_STR("string -> time from a string in ISO 8601 format")}, - - {"__reduce_ex__", time_reduce_ex, METH_VARARGS, - PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")}, - - {"__reduce__", time_reduce, METH_NOARGS, - PyDoc_STR("__reduce__() -> (cls, state)")}, + DATETIME_TIME___REDUCE_EX___METHODDEF + DATETIME_TIME___REDUCE___METHODDEF {NULL, NULL} }; -static const char time_doc[] = -PyDoc_STR("time([hour[, minute[, second[, microsecond[, tzinfo]]]]]) --> a time object\n\ -\n\ -All arguments are optional. tzinfo may be None, or an instance of\n\ -a tzinfo subclass. The remaining arguments may be ints.\n"); - static PyTypeObject PyDateTime_TimeType = { PyVarObject_HEAD_INIT(NULL, 0) "datetime.time", /* tp_name */ @@ -5213,8 +5268,8 @@ static PyTypeObject PyDateTime_TimeType = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - time_doc, /* tp_doc */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + datetime_time__doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ time_richcompare, /* tp_richcompare */ @@ -5300,11 +5355,6 @@ static PyGetSetDef datetime_getset[] = { * Constructors. */ -static char *datetime_kws[] = { - "year", "month", "day", "hour", "minute", "second", - "microsecond", "tzinfo", "fold", NULL -}; - static PyObject * datetime_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo) { @@ -5340,20 +5390,10 @@ datetime_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo) static PyObject * datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw) { - PyObject *self = NULL; - int year; - int month; - int day; - int hour = 0; - int minute = 0; - int second = 0; - int usecond = 0; - int fold = 0; - PyObject *tzinfo = Py_None; - /* Check for invocation from pickle with __getstate__ state */ if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2) { PyObject *state = PyTuple_GET_ITEM(args, 0); + PyObject *tzinfo = Py_None; if (PyTuple_GET_SIZE(args) == 2) { tzinfo = PyTuple_GET_ITEM(args, 1); } @@ -5379,22 +5419,46 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw) } return NULL; } - self = datetime_from_pickle(type, state, tzinfo); + PyObject *self = datetime_from_pickle(type, state, tzinfo); Py_DECREF(state); return self; } } - tzinfo = Py_None; } - if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO$i", datetime_kws, - &year, &month, &day, &hour, &minute, - &second, &usecond, &tzinfo, &fold)) { - self = new_datetime_ex2(year, month, day, - hour, minute, second, usecond, - tzinfo, fold, type); - } - return self; + return datetime_datetime(type, args, kw); +} + +/*[clinic input] +@classmethod +datetime.datetime.__new__ + + year: int + month: int + day: int + hour: int = 0 + minute: int = 0 + second: int = 0 + microsecond: int = 0 + tzinfo: object = None + * + fold: int = 0 + +A combination of a date and a time. + +The year, month and day arguments are required. tzinfo may be None, or an +instance of a tzinfo subclass. The remaining arguments may be ints. +[clinic start generated code]*/ + +static PyObject * +datetime_datetime_impl(PyTypeObject *type, int year, int month, int day, + int hour, int minute, int second, int microsecond, + PyObject *tzinfo, int fold) +/*[clinic end generated code: output=47983ddb47d36037 input=2af468d7a9c1e568]*/ +{ + return new_datetime_ex2(year, month, day, + hour, minute, second, microsecond, + tzinfo, fold, type); } /* TM_FUNC is the shared type of _PyTime_localtime() and @@ -5451,7 +5515,7 @@ local(long long u) * Pass localtime or gmtime for f, to control the interpretation of timet. */ static PyObject * -datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, +datetime_from_timet_and_us(PyTypeObject *cls, TM_FUNC f, time_t timet, int us, PyObject *tzinfo) { struct tm tm; @@ -5523,7 +5587,7 @@ 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(PyTypeObject *cls, TM_FUNC f, PyObject *timestamp, PyObject *tzinfo) { time_t timet; @@ -5541,7 +5605,7 @@ datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp, * gmtime for f as appropriate. */ static PyObject * -datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo) +datetime_best_possible(PyTypeObject *cls, TM_FUNC f, PyObject *tzinfo) { PyTime_t ts; if (PyTime_Time(&ts) < 0) { @@ -5584,7 +5648,7 @@ datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) if (check_tzinfo_subclass(tz) < 0) return NULL; - self = datetime_best_possible((PyObject *)type, + self = datetime_best_possible(type, tz == Py_None ? _PyTime_localtime : _PyTime_gmtime, tz); @@ -5600,8 +5664,16 @@ datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) /* Return best possible UTC time -- this isn't constrained by the * precision of a timestamp. */ +/*[clinic input] +@classmethod +datetime.datetime.utcnow + +Return a new datetime representing UTC day and time. +[clinic start generated code]*/ + static PyObject * -datetime_utcnow(PyObject *cls, PyObject *dummy) +datetime_datetime_utcnow_impl(PyTypeObject *type) +/*[clinic end generated code: output=cfcfe71c6c916ba9 input=576eff2b222b80a1]*/ { if (PyErr_WarnEx(PyExc_DeprecationWarning, "datetime.datetime.utcnow() is deprecated and scheduled for removal in a " @@ -5610,25 +5682,32 @@ datetime_utcnow(PyObject *cls, PyObject *dummy) { return NULL; } - return datetime_best_possible(cls, _PyTime_gmtime, Py_None); + return datetime_best_possible(type, _PyTime_gmtime, Py_None); } -/* Return new local datetime from timestamp (Python timestamp -- a double). */ +/*[clinic input] +@classmethod +datetime.datetime.fromtimestamp + + timestamp: object + tz as tzinfo: object = None + +Create a datetime from a POSIX timestamp. + +The timestamp is a number, e.g. created via time.time(), that is interpreted +as local time. +[clinic start generated code]*/ + static PyObject * -datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) +datetime_datetime_fromtimestamp_impl(PyTypeObject *type, PyObject *timestamp, + PyObject *tzinfo) +/*[clinic end generated code: output=9c47ea2b2ebdaded input=34721a5facc94215]*/ { PyObject *self; - PyObject *timestamp; - PyObject *tzinfo = Py_None; - static char *keywords[] = {"timestamp", "tz", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp", - keywords, ×tamp, &tzinfo)) - return NULL; if (check_tzinfo_subclass(tzinfo) < 0) return NULL; - self = datetime_from_timestamp(cls, + self = datetime_from_timestamp(type, tzinfo == Py_None ? _PyTime_localtime : _PyTime_gmtime, timestamp, @@ -5642,9 +5721,35 @@ datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) return self; } -/* Return new UTC datetime from timestamp (Python timestamp -- a double). */ +/* This is a wrapper for API compatibility with the public C API. */ +static PyObject * +datetime_datetime_fromtimestamp_capi(PyObject *cls, PyObject *args, PyObject *kw) +{ + PyObject *timestamp; + PyObject *tzinfo = Py_None; + static char *keywords[] = {"timestamp", "tz", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp", + keywords, ×tamp, &tzinfo)) + return NULL; + return datetime_datetime_fromtimestamp_impl((PyTypeObject *)cls, + timestamp, tzinfo); +} + +/*[clinic input] +@classmethod +datetime.datetime.utcfromtimestamp + + timestamp: object + / + +Create a naive UTC datetime from a POSIX timestamp. +[clinic start generated code]*/ + static PyObject * -datetime_utcfromtimestamp(PyObject *cls, PyObject *args) +datetime_datetime_utcfromtimestamp_impl(PyTypeObject *type, + PyObject *timestamp) +/*[clinic end generated code: output=66d0b1741d788fd2 input=13fabd4296b1c206]*/ { if (PyErr_WarnEx(PyExc_DeprecationWarning, "datetime.datetime.utcfromtimestamp() is deprecated and scheduled for removal " @@ -5653,23 +5758,27 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args) { return NULL; } - PyObject *timestamp; - PyObject *result = NULL; - if (PyArg_ParseTuple(args, "O:utcfromtimestamp", ×tamp)) - result = datetime_from_timestamp(cls, _PyTime_gmtime, timestamp, - Py_None); - return result; + return datetime_from_timestamp(type, _PyTime_gmtime, timestamp, Py_None); } -/* Return new datetime from _strptime.strptime_datetime_datetime(). */ +/*[clinic input] +@classmethod +datetime.datetime.strptime + + string: unicode + format: unicode + / + +Parse string according to the given date and time format (like time.strptime()). +[clinic start generated code]*/ + static PyObject * -datetime_strptime(PyObject *cls, PyObject *args) +datetime_datetime_strptime_impl(PyTypeObject *type, PyObject *string, + PyObject *format) +/*[clinic end generated code: output=af2c2d024f3203f5 input=b3918835524a1f22]*/ { - PyObject *string, *format, *result; - - if (!PyArg_ParseTuple(args, "UU:strptime", &string, &format)) - return NULL; + PyObject *result; PyObject *module = PyImport_Import(&_Py_ID(_strptime)); if (module == NULL) { @@ -5677,42 +5786,43 @@ datetime_strptime(PyObject *cls, PyObject *args) } result = PyObject_CallMethodObjArgs(module, &_Py_ID(_strptime_datetime_datetime), - cls, string, format, NULL); + (PyObject *)type, string, format, NULL); Py_DECREF(module); return result; } -/* Return new datetime from date/datetime and time arguments. */ +/*[clinic input] +@classmethod +datetime.datetime.combine + + date: object(subclass_of="DATE_TYPE(NO_STATE)") + time: object(subclass_of="TIME_TYPE(NO_STATE)") + tzinfo: object = NULL + +Construct a datetime from a given date and a given time. +[clinic start generated code]*/ + static PyObject * -datetime_combine(PyObject *cls, PyObject *args, PyObject *kw) +datetime_datetime_combine_impl(PyTypeObject *type, PyObject *date, + PyObject *time, PyObject *tzinfo) +/*[clinic end generated code: output=a10f3cbb90f4d0aa input=4fcf0743288d0bab]*/ { - static char *keywords[] = {"date", "time", "tzinfo", NULL}; - PyObject *date; - PyObject *time; - PyObject *tzinfo = NULL; - PyObject *result = NULL; - - if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!|O:combine", keywords, - DATE_TYPE(NO_STATE), &date, - TIME_TYPE(NO_STATE), &time, &tzinfo)) { - if (tzinfo == NULL) { - if (HASTZINFO(time)) - tzinfo = ((PyDateTime_Time *)time)->tzinfo; - else - tzinfo = Py_None; - } - result = new_datetime_subclass_fold_ex(GET_YEAR(date), - GET_MONTH(date), - GET_DAY(date), - TIME_GET_HOUR(time), - TIME_GET_MINUTE(time), - TIME_GET_SECOND(time), - TIME_GET_MICROSECOND(time), - tzinfo, - TIME_GET_FOLD(time), - cls); + if (tzinfo == NULL) { + if (HASTZINFO(time)) + tzinfo = ((PyDateTime_Time *)time)->tzinfo; + else + tzinfo = Py_None; } - return result; + return new_datetime_subclass_fold_ex(GET_YEAR(date), + GET_MONTH(date), + GET_DAY(date), + TIME_GET_HOUR(time), + TIME_GET_MINUTE(time), + TIME_GET_SECOND(time), + TIME_GET_MICROSECOND(time), + tzinfo, + TIME_GET_FOLD(time), + type); } static PyObject * @@ -5870,23 +5980,26 @@ _find_isoformat_datetime_separator(const char *dtstr, Py_ssize_t len) { } } -static PyObject * -datetime_fromisoformat(PyObject *cls, PyObject *dtstr) -{ - assert(dtstr != NULL); +/*[clinic input] +@classmethod +datetime.datetime.fromisoformat - if (!PyUnicode_Check(dtstr)) { - PyErr_SetString(PyExc_TypeError, - "fromisoformat: argument must be str"); - return NULL; - } + string: unicode + / +Construct a date from a string in ISO 8601 format. +[clinic start generated code]*/ + +static PyObject * +datetime_datetime_fromisoformat_impl(PyTypeObject *type, PyObject *string) +/*[clinic end generated code: output=1800a952fcab79d9 input=d517b158209ded42]*/ +{ // We only need to sanitize this string if the separator is a surrogate // character. In the situation where the separator location is ambiguous, // we don't have to sanitize it anything because that can only happen when // the separator is either '-' or a number. This should mostly be a noop // but it makes the reference counting easier if we still sanitize. - PyObject *dtstr_clean = _sanitize_isoformat_str(dtstr); + PyObject *dtstr_clean = _sanitize_isoformat_str(string); if (dtstr_clean == NULL) { goto invalid_string_error; } @@ -5974,7 +6087,7 @@ datetime_fromisoformat(PyObject *cls, PyObject *dtstr) } } PyObject *dt = new_datetime_subclass_ex(year, month, day, hour, minute, - second, microsecond, tzinfo, cls); + second, microsecond, tzinfo, type); Py_DECREF(tzinfo); Py_DECREF(dtstr_clean); @@ -5987,7 +6100,7 @@ datetime_fromisoformat(PyObject *cls, PyObject *dtstr) return NULL; invalid_string_error: - PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr); + PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", string); error: Py_XDECREF(dtstr_clean); @@ -6064,7 +6177,7 @@ add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta, return new_datetime_subclass_ex(year, month, day, hour, minute, second, microsecond, HASTZINFO(date) ? date->tzinfo : Py_None, - (PyObject *)Py_TYPE(date)); + Py_TYPE(date)); } static PyObject * @@ -6226,18 +6339,38 @@ datetime_str(PyObject *op) return res; } +/*[clinic input] +datetime.datetime.isoformat + + sep: int(accept={str}, c_default="'T'", py_default="'T'") = ord('T') + timespec: str(c_default="NULL") = 'auto' + +Return the time formatted according to ISO. + +The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'. +By default, the fractional part is omitted if self.microsecond == 0. + +If self.tzinfo is not None, the UTC offset is also attached, giving +a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'. + +Optional argument sep specifies the separator between date and +time, default 'T'. + +The optional argument timespec specifies the number of additional +terms of the time to include. Valid options are 'auto', 'hours', +'minutes', 'seconds', 'milliseconds' and 'microseconds'. +[clinic start generated code]*/ + static PyObject * -datetime_isoformat(PyObject *op, PyObject *args, PyObject *kw) +datetime_datetime_isoformat_impl(PyDateTime_DateTime *self, int sep, + const char *timespec) +/*[clinic end generated code: output=9b6ce1383189b0bf input=2fa2512172ccf5d5]*/ { - int sep = 'T'; - char *timespec = NULL; - static char *keywords[] = {"sep", "timespec", NULL}; char buffer[100]; - PyDateTime_DateTime *self = PyDateTime_CAST(op); PyObject *result = NULL; int us = DATE_GET_MICROSECOND(self); - static const char *specs[][2] = { + static const char * const specs[][2] = { {"hours", "%04d-%02d-%02d%c%02d"}, {"minutes", "%04d-%02d-%02d%c%02d:%02d"}, {"seconds", "%04d-%02d-%02d%c%02d:%02d:%02d"}, @@ -6246,9 +6379,6 @@ datetime_isoformat(PyObject *op, PyObject *args, PyObject *kw) }; size_t given_spec; - if (!PyArg_ParseTupleAndKeywords(args, kw, "|Cs:isoformat", keywords, &sep, ×pec)) - return NULL; - if (timespec == NULL || strcmp(timespec, "auto") == 0) { if (us == 0) { /* seconds */ @@ -6286,7 +6416,7 @@ datetime_isoformat(PyObject *op, PyObject *args, PyObject *kw) return result; /* We need to append the UTC offset. */ - if (format_utcoffset(buffer, sizeof(buffer), ":", self->tzinfo, op) < 0) { + if (format_utcoffset(buffer, sizeof(buffer), ":", self->tzinfo, (PyObject *)self) < 0) { Py_DECREF(result); return NULL; } @@ -6416,8 +6546,7 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) PyDateTime_Delta *delta; assert(offset1 != offset2); /* else last "if" handled it */ - delta = (PyDateTime_Delta *)datetime_subtract((PyObject *)self, - other); + delta = (PyDateTime_Delta *)datetime_subtract(self, other); if (delta == NULL) goto done; diff = GET_TD_DAYS(delta); @@ -6541,7 +6670,7 @@ datetime_datetime_replace_impl(PyDateTime_DateTime *self, int year, { return new_datetime_subclass_fold_ex(year, month, day, hour, minute, second, microsecond, tzinfo, fold, - (PyObject *)Py_TYPE(self)); + Py_TYPE(self)); } static PyObject * @@ -6677,20 +6806,23 @@ local_timezone_from_local(PyDateTime_DateTime *local_dt) return local_timezone_from_timestamp(timestamp); } +/*[clinic input] +datetime.datetime.astimezone + + tz as tzinfo: object = None + +Convert to local time in new timezone tz. +[clinic start generated code]*/ + static PyObject * -datetime_astimezone(PyObject *op, PyObject *args, PyObject *kw) +datetime_datetime_astimezone_impl(PyDateTime_DateTime *self, + PyObject *tzinfo) +/*[clinic end generated code: output=ae2263d04e944537 input=9c675c8595009935]*/ { - PyDateTime_DateTime *self = PyDateTime_CAST(op); PyDateTime_DateTime *result; PyObject *offset; PyObject *temp; PyObject *self_tzinfo; - PyObject *tzinfo = Py_None; - static char *keywords[] = {"tz", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kw, "|O:astimezone", keywords, - &tzinfo)) - return NULL; if (check_tzinfo_subclass(tzinfo) == -1) return NULL; @@ -6987,22 +7119,29 @@ datetime_getstate(PyDateTime_DateTime *self, int proto) return result; } +/*[clinic input] +datetime.datetime.__reduce_ex__ + + proto: int + / +[clinic start generated code]*/ + static PyObject * -datetime_reduce_ex(PyObject *op, PyObject *args) +datetime_datetime___reduce_ex___impl(PyDateTime_DateTime *self, int proto) +/*[clinic end generated code: output=53d712ce3e927735 input=bab748e49ffb30c3]*/ { - int proto; - if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto)) - return NULL; - - PyDateTime_DateTime *self = PyDateTime_CAST(op); return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, proto)); } +/*[clinic input] +datetime.datetime.__reduce__ +[clinic start generated code]*/ + static PyObject * -datetime_reduce(PyObject *op, PyObject *Py_UNUSED(arg)) +datetime_datetime___reduce___impl(PyDateTime_DateTime *self) +/*[clinic end generated code: output=6794df9ea75666cf input=cadbbeb3bf3bf94c]*/ { - PyDateTime_DateTime *self = PyDateTime_CAST(op); return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, 2)); } @@ -7012,31 +7151,12 @@ static PyMethodDef datetime_methods[] = { /* Class methods: */ DATETIME_DATETIME_NOW_METHODDEF - - {"utcnow", datetime_utcnow, - METH_NOARGS | METH_CLASS, - PyDoc_STR("Return a new datetime representing UTC day and time.")}, - - {"fromtimestamp", _PyCFunction_CAST(datetime_fromtimestamp), - METH_VARARGS | METH_KEYWORDS | METH_CLASS, - PyDoc_STR("timestamp[, tz] -> tz's local time from POSIX timestamp.")}, - - {"utcfromtimestamp", datetime_utcfromtimestamp, - METH_VARARGS | METH_CLASS, - PyDoc_STR("Construct a naive UTC datetime from a POSIX timestamp.")}, - - {"strptime", datetime_strptime, - METH_VARARGS | METH_CLASS, - PyDoc_STR("string, format -> new datetime parsed from a string " - "(like time.strptime()).")}, - - {"combine", _PyCFunction_CAST(datetime_combine), - METH_VARARGS | METH_KEYWORDS | METH_CLASS, - PyDoc_STR("date, time -> datetime with same date and time fields")}, - - {"fromisoformat", datetime_fromisoformat, - METH_O | METH_CLASS, - PyDoc_STR("string -> datetime from a string in most ISO 8601 formats")}, + DATETIME_DATETIME_UTCNOW_METHODDEF + DATETIME_DATETIME_FROMTIMESTAMP_METHODDEF + DATETIME_DATETIME_UTCFROMTIMESTAMP_METHODDEF + DATETIME_DATETIME_STRPTIME_METHODDEF + DATETIME_DATETIME_COMBINE_METHODDEF + DATETIME_DATETIME_FROMISOFORMAT_METHODDEF /* Instance methods: */ @@ -7061,15 +7181,7 @@ static PyMethodDef datetime_methods[] = { {"utctimetuple", datetime_utctimetuple, METH_NOARGS, PyDoc_STR("Return UTC time tuple, compatible with time.localtime().")}, - {"isoformat", _PyCFunction_CAST(datetime_isoformat), METH_VARARGS | METH_KEYWORDS, - PyDoc_STR("[sep] -> string in ISO 8601 format, " - "YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n" - "sep is used to separate the year from the time, and " - "defaults to 'T'.\n" - "The optional argument timespec specifies the number " - "of additional terms\nof the time to include. Valid " - "options are 'auto', 'hours', 'minutes',\n'seconds', " - "'milliseconds' and 'microseconds'.\n")}, + DATETIME_DATETIME_ISOFORMAT_METHODDEF {"utcoffset", datetime_utcoffset, METH_NOARGS, PyDoc_STR("Return self.tzinfo.utcoffset(self).")}, @@ -7085,24 +7197,13 @@ static PyMethodDef datetime_methods[] = { {"__replace__", _PyCFunction_CAST(datetime_datetime_replace), METH_FASTCALL | METH_KEYWORDS, PyDoc_STR("__replace__($self, /, **changes)\n--\n\nThe same as replace().")}, - {"astimezone", _PyCFunction_CAST(datetime_astimezone), METH_VARARGS | METH_KEYWORDS, - PyDoc_STR("tz -> convert to local time in new timezone tz\n")}, - - {"__reduce_ex__", datetime_reduce_ex, METH_VARARGS, - PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")}, - - {"__reduce__", datetime_reduce, METH_NOARGS, - PyDoc_STR("__reduce__() -> (cls, state)")}, + DATETIME_DATETIME_ASTIMEZONE_METHODDEF + DATETIME_DATETIME___REDUCE_EX___METHODDEF + DATETIME_DATETIME___REDUCE___METHODDEF {NULL, NULL} }; -static const char datetime_doc[] = -PyDoc_STR("datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])\n\ -\n\ -The year, month and day arguments are required. tzinfo may be None, or an\n\ -instance of a tzinfo subclass. The remaining arguments may be ints.\n"); - static PyNumberMethods datetime_as_number = { datetime_add, /* nb_add */ datetime_subtract, /* nb_subtract */ @@ -7136,8 +7237,8 @@ static PyTypeObject PyDateTime_DateTimeType = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - datetime_doc, /* tp_doc */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + datetime_datetime__doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ datetime_richcompare, /* tp_richcompare */ @@ -7195,7 +7296,7 @@ static PyDateTime_CAPI capi = { .Time_FromTime = new_time_ex, .Delta_FromDelta = new_delta_ex, .TimeZone_FromTimeZone = new_timezone, - .DateTime_FromTimestamp = datetime_fromtimestamp, + .DateTime_FromTimestamp = datetime_datetime_fromtimestamp_capi, .Date_FromTimestamp = datetime_date_fromtimestamp_capi, .DateTime_FromDateAndTimeAndFold = new_datetime_ex2, .Time_FromTimeAndFold = new_time_ex2, diff --git a/Modules/clinic/_datetimemodule.c.h b/Modules/clinic/_datetimemodule.c.h index 18e6129fad8a89..7c4bd5503ed56b 100644 --- a/Modules/clinic/_datetimemodule.c.h +++ b/Modules/clinic/_datetimemodule.c.h @@ -8,6 +8,206 @@ preserve #endif #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +PyDoc_STRVAR(delta_new__doc__, +"timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0,\n" +" hours=0, weeks=0)\n" +"--\n" +"\n" +"Difference between two datetime values.\n" +"\n" +"All arguments are optional and default to 0.\n" +"Arguments may be integers or floats, and may be positive or negative."); + +static PyObject * +delta_new_impl(PyTypeObject *type, PyObject *days, PyObject *seconds, + PyObject *microseconds, PyObject *milliseconds, + PyObject *minutes, PyObject *hours, PyObject *weeks); + +static PyObject * +delta_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 7 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(days), &_Py_ID(seconds), &_Py_ID(microseconds), &_Py_ID(milliseconds), &_Py_ID(minutes), &_Py_ID(hours), &_Py_ID(weeks), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"days", "seconds", "microseconds", "milliseconds", "minutes", "hours", "weeks", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "timedelta", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[7]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + PyObject *days = NULL; + PyObject *seconds = NULL; + PyObject *microseconds = NULL; + PyObject *milliseconds = NULL; + PyObject *minutes = NULL; + PyObject *hours = NULL; + PyObject *weeks = NULL; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 0, /*maxpos*/ 7, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + days = fastargs[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[1]) { + seconds = fastargs[1]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[2]) { + microseconds = fastargs[2]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[3]) { + milliseconds = fastargs[3]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[4]) { + minutes = fastargs[4]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[5]) { + hours = fastargs[5]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + weeks = fastargs[6]; +skip_optional_pos: + return_value = delta_new_impl(type, days, seconds, microseconds, milliseconds, minutes, hours, weeks); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date__doc__, +"date(year, month, day)\n" +"--\n" +"\n" +"Concrete date type."); + +static PyObject * +datetime_date_impl(PyTypeObject *type, int year, int month, int day); + +static PyObject * +datetime_date(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(year), &_Py_ID(month), &_Py_ID(day), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"year", "month", "day", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "date", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + int year; + int month; + int day; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 3, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + year = PyLong_AsInt(fastargs[0]); + if (year == -1 && PyErr_Occurred()) { + goto exit; + } + month = PyLong_AsInt(fastargs[1]); + if (month == -1 && PyErr_Occurred()) { + goto exit; + } + day = PyLong_AsInt(fastargs[2]); + if (day == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = datetime_date_impl(type, year, month, day); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date_today__doc__, +"today($type, /)\n" +"--\n" +"\n" +"Current date or datetime.\n" +"\n" +"Equivalent to 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(PyObject *type, PyObject *Py_UNUSED(ignored)) +{ + return datetime_date_today_impl((PyTypeObject *)type); +} + PyDoc_STRVAR(datetime_date_fromtimestamp__doc__, "fromtimestamp($type, timestamp, /)\n" "--\n" @@ -33,12 +233,83 @@ datetime_date_fromtimestamp(PyObject *type, PyObject *timestamp) return return_value; } +PyDoc_STRVAR(datetime_date_fromordinal__doc__, +"fromordinal($type, ordinal, /)\n" +"--\n" +"\n" +"Construct a date from a proleptic Gregorian ordinal.\n" +"\n" +"January 1 of year 1 is day 1. Only the year, month and day are\n" +"non-zero in the result."); + +#define DATETIME_DATE_FROMORDINAL_METHODDEF \ + {"fromordinal", (PyCFunction)datetime_date_fromordinal, METH_O|METH_CLASS, datetime_date_fromordinal__doc__}, + static PyObject * -iso_calendar_date_new_impl(PyTypeObject *type, int year, int week, - int weekday); +datetime_date_fromordinal_impl(PyTypeObject *type, int ordinal); static PyObject * -iso_calendar_date_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +datetime_date_fromordinal(PyObject *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((PyTypeObject *)type, ordinal); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date_fromisoformat__doc__, +"fromisoformat($type, string, /)\n" +"--\n" +"\n" +"Construct a date from a string in ISO 8601 format."); + +#define DATETIME_DATE_FROMISOFORMAT_METHODDEF \ + {"fromisoformat", (PyCFunction)datetime_date_fromisoformat, METH_O|METH_CLASS, datetime_date_fromisoformat__doc__}, + +static PyObject * +datetime_date_fromisoformat_impl(PyTypeObject *type, PyObject *string); + +static PyObject * +datetime_date_fromisoformat(PyObject *type, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *string; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("fromisoformat", "argument", "str", arg); + goto exit; + } + string = arg; + return_value = datetime_date_fromisoformat_impl((PyTypeObject *)type, string); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date_fromisocalendar__doc__, +"fromisocalendar($type, /, year, week, day)\n" +"--\n" +"\n" +"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_CAST(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(PyObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -52,7 +323,7 @@ iso_calendar_date_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(year), &_Py_ID(week), &_Py_ID(weekday), }, + .ob_item = { &_Py_ID(year), &_Py_ID(week), &_Py_ID(day), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -61,58 +332,1293 @@ iso_calendar_date_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"year", "week", "weekday", NULL}; + static const char * const _keywords[] = {"year", "week", "day", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "IsoCalendarDate", + .fname = "fromisocalendar", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[3]; - PyObject * const *fastargs; - Py_ssize_t nargs = PyTuple_GET_SIZE(args); int year; int week; - int weekday; + int day; - fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, /*minpos*/ 3, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!fastargs) { + if (!args) { goto exit; } - year = PyLong_AsInt(fastargs[0]); + year = PyLong_AsInt(args[0]); if (year == -1 && PyErr_Occurred()) { goto exit; } - week = PyLong_AsInt(fastargs[1]); + week = PyLong_AsInt(args[1]); if (week == -1 && PyErr_Occurred()) { goto exit; } - weekday = PyLong_AsInt(fastargs[2]); - if (weekday == -1 && PyErr_Occurred()) { + day = PyLong_AsInt(args[2]); + if (day == -1 && PyErr_Occurred()) { goto exit; } - return_value = iso_calendar_date_new_impl(type, year, week, weekday); + return_value = datetime_date_fromisocalendar_impl((PyTypeObject *)type, year, week, day); exit: return return_value; } -PyDoc_STRVAR(datetime_date_replace__doc__, -"replace($self, /, year=unchanged, month=unchanged, day=unchanged)\n" +PyDoc_STRVAR(datetime_date_strptime__doc__, +"strptime($type, string, format, /)\n" "--\n" "\n" -"Return date with new specified fields."); +"Parse string according to the given date format (like time.strptime())."); + +#define DATETIME_DATE_STRPTIME_METHODDEF \ + {"strptime", _PyCFunction_CAST(datetime_date_strptime), METH_FASTCALL|METH_CLASS, datetime_date_strptime__doc__}, + +static PyObject * +datetime_date_strptime_impl(PyTypeObject *type, PyObject *string, + PyObject *format); + +static PyObject * +datetime_date_strptime(PyObject *type, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *string; + PyObject *format; + + if (!_PyArg_CheckPositional("strptime", nargs, 2, 2)) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("strptime", "argument 1", "str", args[0]); + goto exit; + } + string = args[0]; + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("strptime", "argument 2", "str", args[1]); + goto exit; + } + format = args[1]; + return_value = datetime_date_strptime_impl((PyTypeObject *)type, string, format); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date_strftime__doc__, +"strftime($self, /, format)\n" +"--\n" +"\n" +"Format using strftime().\n" +"\n" +"Example: \"%d/%m/%Y, %H:%M:%S\"."); + +#define DATETIME_DATE_STRFTIME_METHODDEF \ + {"strftime", _PyCFunction_CAST(datetime_date_strftime), METH_FASTCALL|METH_KEYWORDS, datetime_date_strftime__doc__}, + +static PyObject * +datetime_date_strftime_impl(PyObject *self, PyObject *format); + +static PyObject * +datetime_date_strftime(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(format), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"format", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "strftime", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *format; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("strftime", "argument 'format'", "str", args[0]); + goto exit; + } + format = args[0]; + return_value = datetime_date_strftime_impl(self, format); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date___format____doc__, +"__format__($self, format, /)\n" +"--\n" +"\n" +"Formats self with strftime."); + +#define DATETIME_DATE___FORMAT___METHODDEF \ + {"__format__", (PyCFunction)datetime_date___format__, METH_O, datetime_date___format____doc__}, + +static PyObject * +datetime_date___format___impl(PyObject *self, PyObject *format); + +static PyObject * +datetime_date___format__(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *format; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("__format__", "argument", "str", arg); + goto exit; + } + format = arg; + return_value = datetime_date___format___impl(self, format); + +exit: + return return_value; +} + +static PyObject * +iso_calendar_date_new_impl(PyTypeObject *type, int year, int week, + int weekday); + +static PyObject * +iso_calendar_date_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(year), &_Py_ID(week), &_Py_ID(weekday), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"year", "week", "weekday", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "IsoCalendarDate", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + int year; + int week; + int weekday; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 3, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + year = PyLong_AsInt(fastargs[0]); + if (year == -1 && PyErr_Occurred()) { + goto exit; + } + week = PyLong_AsInt(fastargs[1]); + if (week == -1 && PyErr_Occurred()) { + goto exit; + } + weekday = PyLong_AsInt(fastargs[2]); + if (weekday == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = iso_calendar_date_new_impl(type, year, week, weekday); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date_replace__doc__, +"replace($self, /, year=unchanged, month=unchanged, day=unchanged)\n" +"--\n" +"\n" +"Return date with new specified fields."); + +#define DATETIME_DATE_REPLACE_METHODDEF \ + {"replace", _PyCFunction_CAST(datetime_date_replace), METH_FASTCALL|METH_KEYWORDS, datetime_date_replace__doc__}, + +static PyObject * +datetime_date_replace_impl(PyDateTime_Date *self, int year, int month, + int day); + +static PyObject * +datetime_date_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(year), &_Py_ID(month), &_Py_ID(day), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"year", "month", "day", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "replace", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int year = GET_YEAR(self); + int month = GET_MONTH(self); + int day = GET_DAY(self); + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + year = PyLong_AsInt(args[0]); + if (year == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[1]) { + month = PyLong_AsInt(args[1]); + if (month == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + day = PyLong_AsInt(args[2]); + if (day == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: + return_value = datetime_date_replace_impl((PyDateTime_Date *)self, year, month, day); + +exit: + return return_value; +} + +PyDoc_STRVAR(timezone_new__doc__, +"timezone(offset, name=)\n" +"--\n" +"\n" +"Fixed offset from UTC implementation of tzinfo."); + +static PyObject * +timezone_new_impl(PyTypeObject *type, PyObject *offset, PyObject *name); + +static PyObject * +timezone_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(offset), &_Py_ID(name), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"offset", "name", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "timezone", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; + PyObject *offset; + PyObject *name = NULL; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!PyObject_TypeCheck(fastargs[0], DELTA_TYPE(NO_STATE))) { + _PyArg_BadArgument("timezone", "argument 'offset'", (DELTA_TYPE(NO_STATE))->tp_name, fastargs[0]); + goto exit; + } + offset = fastargs[0]; + if (!noptargs) { + goto skip_optional_pos; + } + if (!PyUnicode_Check(fastargs[1])) { + _PyArg_BadArgument("timezone", "argument 'name'", "str", fastargs[1]); + goto exit; + } + name = fastargs[1]; +skip_optional_pos: + return_value = timezone_new_impl(type, offset, name); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time__doc__, +"time(hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0)\n" +"--\n" +"\n" +"Time with time zone.\n" +"\n" +"All arguments are optional. tzinfo may be None, or an instance of\n" +"a tzinfo subclass. The remaining arguments may be ints."); + +static PyObject * +datetime_time_impl(PyTypeObject *type, int hour, int minute, int second, + int microsecond, PyObject *tzinfo, int fold); + +static PyObject * +datetime_time(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 6 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(hour), &_Py_ID(minute), &_Py_ID(second), &_Py_ID(microsecond), &_Py_ID(tzinfo), &_Py_ID(fold), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"hour", "minute", "second", "microsecond", "tzinfo", "fold", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "time", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[6]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + int hour = 0; + int minute = 0; + int second = 0; + int microsecond = 0; + PyObject *tzinfo = Py_None; + int fold = 0; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 0, /*maxpos*/ 5, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + hour = PyLong_AsInt(fastargs[0]); + if (hour == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[1]) { + minute = PyLong_AsInt(fastargs[1]); + if (minute == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[2]) { + second = PyLong_AsInt(fastargs[2]); + if (second == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[3]) { + microsecond = PyLong_AsInt(fastargs[3]); + if (microsecond == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[4]) { + tzinfo = fastargs[4]; + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + fold = PyLong_AsInt(fastargs[5]); + if (fold == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_kwonly: + return_value = datetime_time_impl(type, hour, minute, second, microsecond, tzinfo, fold); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time_strptime__doc__, +"strptime($type, string, format, /)\n" +"--\n" +"\n" +"Parse string according to the given time format (like time.strptime())."); + +#define DATETIME_TIME_STRPTIME_METHODDEF \ + {"strptime", _PyCFunction_CAST(datetime_time_strptime), METH_FASTCALL|METH_CLASS, datetime_time_strptime__doc__}, + +static PyObject * +datetime_time_strptime_impl(PyTypeObject *type, PyObject *string, + PyObject *format); + +static PyObject * +datetime_time_strptime(PyObject *type, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *string; + PyObject *format; + + if (!_PyArg_CheckPositional("strptime", nargs, 2, 2)) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("strptime", "argument 1", "str", args[0]); + goto exit; + } + string = args[0]; + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("strptime", "argument 2", "str", args[1]); + goto exit; + } + format = args[1]; + return_value = datetime_time_strptime_impl((PyTypeObject *)type, string, format); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time_isoformat__doc__, +"isoformat($self, /, timespec=\'auto\')\n" +"--\n" +"\n" +"Return the time formatted according to ISO.\n" +"\n" +"The full format is \'HH:MM:SS.mmmmmm+zz:zz\'. By default, the fractional\n" +"part is omitted if self.microsecond == 0.\n" +"\n" +"The optional argument timespec specifies the number of additional\n" +"terms of the time to include. Valid options are \'auto\', \'hours\',\n" +"\'minutes\', \'seconds\', \'milliseconds\' and \'microseconds\'."); + +#define DATETIME_TIME_ISOFORMAT_METHODDEF \ + {"isoformat", _PyCFunction_CAST(datetime_time_isoformat), METH_FASTCALL|METH_KEYWORDS, datetime_time_isoformat__doc__}, + +static PyObject * +datetime_time_isoformat_impl(PyDateTime_Time *self, const char *timespec); + +static PyObject * +datetime_time_isoformat(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(timespec), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"timespec", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "isoformat", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + const char *timespec = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("isoformat", "argument 'timespec'", "str", args[0]); + goto exit; + } + Py_ssize_t timespec_length; + timespec = PyUnicode_AsUTF8AndSize(args[0], ×pec_length); + if (timespec == NULL) { + goto exit; + } + if (strlen(timespec) != (size_t)timespec_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +skip_optional_pos: + return_value = datetime_time_isoformat_impl((PyDateTime_Time *)self, timespec); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time_strftime__doc__, +"strftime($self, /, format)\n" +"--\n" +"\n" +"Format using strftime().\n" +"\n" +"The date part of the timestamp passed to underlying strftime should not be used."); + +#define DATETIME_TIME_STRFTIME_METHODDEF \ + {"strftime", _PyCFunction_CAST(datetime_time_strftime), METH_FASTCALL|METH_KEYWORDS, datetime_time_strftime__doc__}, + +static PyObject * +datetime_time_strftime_impl(PyDateTime_Time *self, PyObject *format); + +static PyObject * +datetime_time_strftime(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(format), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"format", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "strftime", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *format; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("strftime", "argument 'format'", "str", args[0]); + goto exit; + } + format = args[0]; + return_value = datetime_time_strftime_impl((PyDateTime_Time *)self, format); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time___format____doc__, +"__format__($self, format, /)\n" +"--\n" +"\n" +"Formats self with strftime."); + +#define DATETIME_TIME___FORMAT___METHODDEF \ + {"__format__", (PyCFunction)datetime_time___format__, METH_O, datetime_time___format____doc__}, + +static PyObject * +datetime_time___format___impl(PyObject *self, PyObject *format); + +static PyObject * +datetime_time___format__(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *format; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("__format__", "argument", "str", arg); + goto exit; + } + format = arg; + return_value = datetime_time___format___impl(self, format); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time_replace__doc__, +"replace($self, /, hour=unchanged, minute=unchanged, second=unchanged,\n" +" microsecond=unchanged, tzinfo=unchanged, *, fold=unchanged)\n" +"--\n" +"\n" +"Return time with new specified fields."); + +#define DATETIME_TIME_REPLACE_METHODDEF \ + {"replace", _PyCFunction_CAST(datetime_time_replace), METH_FASTCALL|METH_KEYWORDS, datetime_time_replace__doc__}, + +static PyObject * +datetime_time_replace_impl(PyDateTime_Time *self, int hour, int minute, + int second, int microsecond, PyObject *tzinfo, + int fold); + +static PyObject * +datetime_time_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 6 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(hour), &_Py_ID(minute), &_Py_ID(second), &_Py_ID(microsecond), &_Py_ID(tzinfo), &_Py_ID(fold), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"hour", "minute", "second", "microsecond", "tzinfo", "fold", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "replace", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[6]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int hour = TIME_GET_HOUR(self); + int minute = TIME_GET_MINUTE(self); + int second = TIME_GET_SECOND(self); + int microsecond = TIME_GET_MICROSECOND(self); + PyObject *tzinfo = HASTZINFO(self) ? ((PyDateTime_Time *)self)->tzinfo : Py_None; + int fold = TIME_GET_FOLD(self); + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 5, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + hour = PyLong_AsInt(args[0]); + if (hour == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[1]) { + minute = PyLong_AsInt(args[1]); + if (minute == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[2]) { + second = PyLong_AsInt(args[2]); + if (second == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[3]) { + microsecond = PyLong_AsInt(args[3]); + if (microsecond == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[4]) { + tzinfo = args[4]; + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + fold = PyLong_AsInt(args[5]); + if (fold == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_kwonly: + return_value = datetime_time_replace_impl((PyDateTime_Time *)self, hour, minute, second, microsecond, tzinfo, fold); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time_fromisoformat__doc__, +"fromisoformat($type, string, /)\n" +"--\n" +"\n" +"Construct a time from a string in ISO 8601 format."); + +#define DATETIME_TIME_FROMISOFORMAT_METHODDEF \ + {"fromisoformat", (PyCFunction)datetime_time_fromisoformat, METH_O|METH_CLASS, datetime_time_fromisoformat__doc__}, + +static PyObject * +datetime_time_fromisoformat_impl(PyTypeObject *type, PyObject *string); + +static PyObject * +datetime_time_fromisoformat(PyObject *type, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *string; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("fromisoformat", "argument", "str", arg); + goto exit; + } + string = arg; + return_value = datetime_time_fromisoformat_impl((PyTypeObject *)type, string); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time___reduce_ex____doc__, +"__reduce_ex__($self, proto, /)\n" +"--\n" +"\n"); + +#define DATETIME_TIME___REDUCE_EX___METHODDEF \ + {"__reduce_ex__", (PyCFunction)datetime_time___reduce_ex__, METH_O, datetime_time___reduce_ex____doc__}, + +static PyObject * +datetime_time___reduce_ex___impl(PyDateTime_Time *self, int proto); + +static PyObject * +datetime_time___reduce_ex__(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + int proto; + + proto = PyLong_AsInt(arg); + if (proto == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = datetime_time___reduce_ex___impl((PyDateTime_Time *)self, proto); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time___reduce____doc__, +"__reduce__($self, /)\n" +"--\n" +"\n"); + +#define DATETIME_TIME___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)datetime_time___reduce__, METH_NOARGS, datetime_time___reduce____doc__}, + +static PyObject * +datetime_time___reduce___impl(PyDateTime_Time *self); + +static PyObject * +datetime_time___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return datetime_time___reduce___impl((PyDateTime_Time *)self); +} + +PyDoc_STRVAR(datetime_datetime__doc__, +"datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0,\n" +" tzinfo=None, *, fold=0)\n" +"--\n" +"\n" +"A combination of a date and a time.\n" +"\n" +"The year, month and day arguments are required. tzinfo may be None, or an\n" +"instance of a tzinfo subclass. The remaining arguments may be ints."); + +static PyObject * +datetime_datetime_impl(PyTypeObject *type, int year, int month, int day, + int hour, int minute, int second, int microsecond, + PyObject *tzinfo, int fold); + +static PyObject * +datetime_datetime(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 9 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(year), &_Py_ID(month), &_Py_ID(day), &_Py_ID(hour), &_Py_ID(minute), &_Py_ID(second), &_Py_ID(microsecond), &_Py_ID(tzinfo), &_Py_ID(fold), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"year", "month", "day", "hour", "minute", "second", "microsecond", "tzinfo", "fold", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "datetime", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[9]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 3; + int year; + int month; + int day; + int hour = 0; + int minute = 0; + int second = 0; + int microsecond = 0; + PyObject *tzinfo = Py_None; + int fold = 0; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 3, /*maxpos*/ 8, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + year = PyLong_AsInt(fastargs[0]); + if (year == -1 && PyErr_Occurred()) { + goto exit; + } + month = PyLong_AsInt(fastargs[1]); + if (month == -1 && PyErr_Occurred()) { + goto exit; + } + day = PyLong_AsInt(fastargs[2]); + if (day == -1 && PyErr_Occurred()) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[3]) { + hour = PyLong_AsInt(fastargs[3]); + if (hour == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[4]) { + minute = PyLong_AsInt(fastargs[4]); + if (minute == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[5]) { + second = PyLong_AsInt(fastargs[5]); + if (second == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[6]) { + microsecond = PyLong_AsInt(fastargs[6]); + if (microsecond == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[7]) { + tzinfo = fastargs[7]; + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + fold = PyLong_AsInt(fastargs[8]); + if (fold == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_kwonly: + return_value = datetime_datetime_impl(type, year, month, day, hour, minute, second, microsecond, tzinfo, fold); + +exit: + return return_value; +} + +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_CAST(datetime_datetime_now), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_datetime_now__doc__}, + +static PyObject * +datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz); + +static PyObject * +datetime_datetime_now(PyObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(tz), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"tz", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "now", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *tz = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + tz = args[0]; +skip_optional_pos: + return_value = datetime_datetime_now_impl((PyTypeObject *)type, tz); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_utcnow__doc__, +"utcnow($type, /)\n" +"--\n" +"\n" +"Return a new datetime representing UTC day and time."); + +#define DATETIME_DATETIME_UTCNOW_METHODDEF \ + {"utcnow", (PyCFunction)datetime_datetime_utcnow, METH_NOARGS|METH_CLASS, datetime_datetime_utcnow__doc__}, + +static PyObject * +datetime_datetime_utcnow_impl(PyTypeObject *type); + +static PyObject * +datetime_datetime_utcnow(PyObject *type, PyObject *Py_UNUSED(ignored)) +{ + return datetime_datetime_utcnow_impl((PyTypeObject *)type); +} + +PyDoc_STRVAR(datetime_datetime_fromtimestamp__doc__, +"fromtimestamp($type, /, timestamp, tz=None)\n" +"--\n" +"\n" +"Create a datetime from a POSIX timestamp.\n" +"\n" +"The timestamp is a number, e.g. created via time.time(), that is interpreted\n" +"as local time."); + +#define DATETIME_DATETIME_FROMTIMESTAMP_METHODDEF \ + {"fromtimestamp", _PyCFunction_CAST(datetime_datetime_fromtimestamp), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_datetime_fromtimestamp__doc__}, + +static PyObject * +datetime_datetime_fromtimestamp_impl(PyTypeObject *type, PyObject *timestamp, + PyObject *tzinfo); + +static PyObject * +datetime_datetime_fromtimestamp(PyObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(timestamp), &_Py_ID(tz), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"timestamp", "tz", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fromtimestamp", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *timestamp; + PyObject *tzinfo = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + timestamp = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + tzinfo = args[1]; +skip_optional_pos: + return_value = datetime_datetime_fromtimestamp_impl((PyTypeObject *)type, timestamp, tzinfo); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_utcfromtimestamp__doc__, +"utcfromtimestamp($type, timestamp, /)\n" +"--\n" +"\n" +"Create a naive UTC datetime from a POSIX timestamp."); + +#define DATETIME_DATETIME_UTCFROMTIMESTAMP_METHODDEF \ + {"utcfromtimestamp", (PyCFunction)datetime_datetime_utcfromtimestamp, METH_O|METH_CLASS, datetime_datetime_utcfromtimestamp__doc__}, + +static PyObject * +datetime_datetime_utcfromtimestamp_impl(PyTypeObject *type, + PyObject *timestamp); + +static PyObject * +datetime_datetime_utcfromtimestamp(PyObject *type, PyObject *timestamp) +{ + PyObject *return_value = NULL; + + return_value = datetime_datetime_utcfromtimestamp_impl((PyTypeObject *)type, timestamp); + + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_strptime__doc__, +"strptime($type, string, format, /)\n" +"--\n" +"\n" +"Parse string according to the given date and time format (like time.strptime())."); + +#define DATETIME_DATETIME_STRPTIME_METHODDEF \ + {"strptime", _PyCFunction_CAST(datetime_datetime_strptime), METH_FASTCALL|METH_CLASS, datetime_datetime_strptime__doc__}, + +static PyObject * +datetime_datetime_strptime_impl(PyTypeObject *type, PyObject *string, + PyObject *format); + +static PyObject * +datetime_datetime_strptime(PyObject *type, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *string; + PyObject *format; + + if (!_PyArg_CheckPositional("strptime", nargs, 2, 2)) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("strptime", "argument 1", "str", args[0]); + goto exit; + } + string = args[0]; + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("strptime", "argument 2", "str", args[1]); + goto exit; + } + format = args[1]; + return_value = datetime_datetime_strptime_impl((PyTypeObject *)type, string, format); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_combine__doc__, +"combine($type, /, date, time, tzinfo=)\n" +"--\n" +"\n" +"Construct a datetime from a given date and a given time."); -#define DATETIME_DATE_REPLACE_METHODDEF \ - {"replace", _PyCFunction_CAST(datetime_date_replace), METH_FASTCALL|METH_KEYWORDS, datetime_date_replace__doc__}, +#define DATETIME_DATETIME_COMBINE_METHODDEF \ + {"combine", _PyCFunction_CAST(datetime_datetime_combine), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_datetime_combine__doc__}, static PyObject * -datetime_date_replace_impl(PyDateTime_Date *self, int year, int month, - int day); +datetime_datetime_combine_impl(PyTypeObject *type, PyObject *date, + PyObject *time, PyObject *tzinfo); static PyObject * -datetime_date_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +datetime_datetime_combine(PyObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -126,7 +1632,7 @@ datetime_date_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, P } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(year), &_Py_ID(month), &_Py_ID(day), }, + .ob_item = { &_Py_ID(date), &_Py_ID(time), &_Py_ID(tzinfo), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -135,200 +1641,107 @@ datetime_date_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, P # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"year", "month", "day", NULL}; + static const char * const _keywords[] = {"date", "time", "tzinfo", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "replace", + .fname = "combine", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[3]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - int year = GET_YEAR(self); - int month = GET_MONTH(self); - int day = GET_DAY(self); + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; + PyObject *date; + PyObject *time; + PyObject *tzinfo = NULL; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 2, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } - if (!noptargs) { - goto skip_optional_pos; - } - if (args[0]) { - year = PyLong_AsInt(args[0]); - if (year == -1 && PyErr_Occurred()) { - goto exit; - } - if (!--noptargs) { - goto skip_optional_pos; - } - } - if (args[1]) { - month = PyLong_AsInt(args[1]); - if (month == -1 && PyErr_Occurred()) { - goto exit; - } - if (!--noptargs) { - goto skip_optional_pos; - } + if (!PyObject_TypeCheck(args[0], DATE_TYPE(NO_STATE))) { + _PyArg_BadArgument("combine", "argument 'date'", (DATE_TYPE(NO_STATE))->tp_name, args[0]); + goto exit; } - day = PyLong_AsInt(args[2]); - if (day == -1 && PyErr_Occurred()) { + date = args[0]; + if (!PyObject_TypeCheck(args[1], TIME_TYPE(NO_STATE))) { + _PyArg_BadArgument("combine", "argument 'time'", (TIME_TYPE(NO_STATE))->tp_name, args[1]); goto exit; } + time = args[1]; + if (!noptargs) { + goto skip_optional_pos; + } + tzinfo = args[2]; skip_optional_pos: - return_value = datetime_date_replace_impl((PyDateTime_Date *)self, year, month, day); + return_value = datetime_datetime_combine_impl((PyTypeObject *)type, date, time, tzinfo); exit: return return_value; } -PyDoc_STRVAR(datetime_time_replace__doc__, -"replace($self, /, hour=unchanged, minute=unchanged, second=unchanged,\n" -" microsecond=unchanged, tzinfo=unchanged, *, fold=unchanged)\n" +PyDoc_STRVAR(datetime_datetime_fromisoformat__doc__, +"fromisoformat($type, string, /)\n" "--\n" "\n" -"Return time with new specified fields."); +"Construct a date from a string in ISO 8601 format."); -#define DATETIME_TIME_REPLACE_METHODDEF \ - {"replace", _PyCFunction_CAST(datetime_time_replace), METH_FASTCALL|METH_KEYWORDS, datetime_time_replace__doc__}, +#define DATETIME_DATETIME_FROMISOFORMAT_METHODDEF \ + {"fromisoformat", (PyCFunction)datetime_datetime_fromisoformat, METH_O|METH_CLASS, datetime_datetime_fromisoformat__doc__}, static PyObject * -datetime_time_replace_impl(PyDateTime_Time *self, int hour, int minute, - int second, int microsecond, PyObject *tzinfo, - int fold); +datetime_datetime_fromisoformat_impl(PyTypeObject *type, PyObject *string); static PyObject * -datetime_time_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +datetime_datetime_fromisoformat(PyObject *type, PyObject *arg) { PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 6 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(hour), &_Py_ID(minute), &_Py_ID(second), &_Py_ID(microsecond), &_Py_ID(tzinfo), &_Py_ID(fold), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"hour", "minute", "second", "microsecond", "tzinfo", "fold", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "replace", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[6]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - int hour = TIME_GET_HOUR(self); - int minute = TIME_GET_MINUTE(self); - int second = TIME_GET_SECOND(self); - int microsecond = TIME_GET_MICROSECOND(self); - PyObject *tzinfo = HASTZINFO(self) ? ((PyDateTime_Time *)self)->tzinfo : Py_None; - int fold = TIME_GET_FOLD(self); + PyObject *string; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 5, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - if (args[0]) { - hour = PyLong_AsInt(args[0]); - if (hour == -1 && PyErr_Occurred()) { - goto exit; - } - if (!--noptargs) { - goto skip_optional_pos; - } - } - if (args[1]) { - minute = PyLong_AsInt(args[1]); - if (minute == -1 && PyErr_Occurred()) { - goto exit; - } - if (!--noptargs) { - goto skip_optional_pos; - } - } - if (args[2]) { - second = PyLong_AsInt(args[2]); - if (second == -1 && PyErr_Occurred()) { - goto exit; - } - if (!--noptargs) { - goto skip_optional_pos; - } - } - if (args[3]) { - microsecond = PyLong_AsInt(args[3]); - if (microsecond == -1 && PyErr_Occurred()) { - goto exit; - } - if (!--noptargs) { - goto skip_optional_pos; - } - } - if (args[4]) { - tzinfo = args[4]; - if (!--noptargs) { - goto skip_optional_pos; - } - } -skip_optional_pos: - if (!noptargs) { - goto skip_optional_kwonly; - } - fold = PyLong_AsInt(args[5]); - if (fold == -1 && PyErr_Occurred()) { + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("fromisoformat", "argument", "str", arg); goto exit; } -skip_optional_kwonly: - return_value = datetime_time_replace_impl((PyDateTime_Time *)self, hour, minute, second, microsecond, tzinfo, fold); + string = arg; + return_value = datetime_datetime_fromisoformat_impl((PyTypeObject *)type, string); exit: return return_value; } -PyDoc_STRVAR(datetime_datetime_now__doc__, -"now($type, /, tz=None)\n" +PyDoc_STRVAR(datetime_datetime_isoformat__doc__, +"isoformat($self, /, sep=\'T\', timespec=\'auto\')\n" "--\n" "\n" -"Returns new datetime object representing current time local to tz.\n" +"Return the time formatted according to ISO.\n" "\n" -" tz\n" -" Timezone object.\n" +"The full format looks like \'YYYY-MM-DD HH:MM:SS.mmmmmm\'.\n" +"By default, the fractional part is omitted if self.microsecond == 0.\n" "\n" -"If no tz is specified, uses local timezone."); +"If self.tzinfo is not None, the UTC offset is also attached, giving\n" +"a full format of \'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM\'.\n" +"\n" +"Optional argument sep specifies the separator between date and\n" +"time, default \'T\'.\n" +"\n" +"The optional argument timespec specifies the number of additional\n" +"terms of the time to include. Valid options are \'auto\', \'hours\',\n" +"\'minutes\', \'seconds\', \'milliseconds\' and \'microseconds\'."); -#define DATETIME_DATETIME_NOW_METHODDEF \ - {"now", _PyCFunction_CAST(datetime_datetime_now), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_datetime_now__doc__}, +#define DATETIME_DATETIME_ISOFORMAT_METHODDEF \ + {"isoformat", _PyCFunction_CAST(datetime_datetime_isoformat), METH_FASTCALL|METH_KEYWORDS, datetime_datetime_isoformat__doc__}, static PyObject * -datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz); +datetime_datetime_isoformat_impl(PyDateTime_DateTime *self, int sep, + const char *timespec); static PyObject * -datetime_datetime_now(PyObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +datetime_datetime_isoformat(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 1 + #define NUM_KEYWORDS 2 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -337,7 +1750,7 @@ datetime_datetime_now(PyObject *type, PyObject *const *args, Py_ssize_t nargs, P } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(tz), }, + .ob_item = { &_Py_ID(sep), &_Py_ID(timespec), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -346,28 +1759,58 @@ datetime_datetime_now(PyObject *type, PyObject *const *args, Py_ssize_t nargs, P # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"tz", NULL}; + static const char * const _keywords[] = {"sep", "timespec", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "now", + .fname = "isoformat", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[1]; + PyObject *argsbuf[2]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *tz = Py_None; + int sep = 'T'; + const char *timespec = NULL; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } if (!noptargs) { goto skip_optional_pos; } - tz = args[0]; + if (args[0]) { + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("isoformat", "argument 'sep'", "a unicode character", args[0]); + goto exit; + } + if (PyUnicode_GET_LENGTH(args[0]) != 1) { + PyErr_Format(PyExc_TypeError, + "isoformat(): argument 'sep' must be a unicode character, " + "not a string of length %zd", + PyUnicode_GET_LENGTH(args[0])); + goto exit; + } + sep = PyUnicode_READ_CHAR(args[0], 0); + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("isoformat", "argument 'timespec'", "str", args[1]); + goto exit; + } + Py_ssize_t timespec_length; + timespec = PyUnicode_AsUTF8AndSize(args[1], ×pec_length); + if (timespec == NULL) { + goto exit; + } + if (strlen(timespec) != (size_t)timespec_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } skip_optional_pos: - return_value = datetime_datetime_now_impl((PyTypeObject *)type, tz); + return_value = datetime_datetime_isoformat_impl((PyDateTime_DateTime *)self, sep, timespec); exit: return return_value; @@ -524,4 +1967,112 @@ datetime_datetime_replace(PyObject *self, PyObject *const *args, Py_ssize_t narg exit: return return_value; } -/*[clinic end generated code: output=809640e747529c72 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(datetime_datetime_astimezone__doc__, +"astimezone($self, /, tz=None)\n" +"--\n" +"\n" +"Convert to local time in new timezone tz."); + +#define DATETIME_DATETIME_ASTIMEZONE_METHODDEF \ + {"astimezone", _PyCFunction_CAST(datetime_datetime_astimezone), METH_FASTCALL|METH_KEYWORDS, datetime_datetime_astimezone__doc__}, + +static PyObject * +datetime_datetime_astimezone_impl(PyDateTime_DateTime *self, + PyObject *tzinfo); + +static PyObject * +datetime_datetime_astimezone(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(tz), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"tz", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "astimezone", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *tzinfo = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + tzinfo = args[0]; +skip_optional_pos: + return_value = datetime_datetime_astimezone_impl((PyDateTime_DateTime *)self, tzinfo); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime___reduce_ex____doc__, +"__reduce_ex__($self, proto, /)\n" +"--\n" +"\n"); + +#define DATETIME_DATETIME___REDUCE_EX___METHODDEF \ + {"__reduce_ex__", (PyCFunction)datetime_datetime___reduce_ex__, METH_O, datetime_datetime___reduce_ex____doc__}, + +static PyObject * +datetime_datetime___reduce_ex___impl(PyDateTime_DateTime *self, int proto); + +static PyObject * +datetime_datetime___reduce_ex__(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + int proto; + + proto = PyLong_AsInt(arg); + if (proto == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = datetime_datetime___reduce_ex___impl((PyDateTime_DateTime *)self, proto); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime___reduce____doc__, +"__reduce__($self, /)\n" +"--\n" +"\n"); + +#define DATETIME_DATETIME___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)datetime_datetime___reduce__, METH_NOARGS, datetime_datetime___reduce____doc__}, + +static PyObject * +datetime_datetime___reduce___impl(PyDateTime_DateTime *self); + +static PyObject * +datetime_datetime___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return datetime_datetime___reduce___impl((PyDateTime_DateTime *)self); +} +/*[clinic end generated code: output=0b8403bc58982e60 input=a9049054013a1b77]*/