]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-136571: Convert more code in datetime to Argument Clinic (GH-136573) main
authorSerhiy Storchaka <storchaka@gmail.com>
Sat, 9 Aug 2025 18:25:49 +0000 (21:25 +0300)
committerGitHub <noreply@github.com>
Sat, 9 Aug 2025 18:25:49 +0000 (18:25 +0000)
This adds signatures for some classes and methods.

date.fromisocalendar() can now raise OverflowError for arguments that
don't fit in the C int.

Doc/library/datetime.rst
Include/internal/pycore_global_objects_fini_generated.h
Include/internal/pycore_global_strings.h
Include/internal/pycore_runtime_init_generated.h
Include/internal/pycore_unicodeobject_generated.h
Lib/_pydatetime.py
Lib/test/datetimetester.py
Lib/test/test_inspect/test_inspect.py
Misc/NEWS.d/next/Library/2025-07-12-14-15-47.gh-issue-136571.muHmBv.rst [new file with mode: 0644]
Modules/_datetimemodule.c
Modules/clinic/_datetimemodule.c.h

index 16ed3215bc2c1aa5af5e101f53fe4ad554b800d8..7010f99c54da0a327de7d489274927528d6f3d9a 100644 (file)
@@ -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
index 5e7dda3a3715a1ed63e67c7a978aa89b022abd5e..ca4744789f1c23523bea362c0cb8d0a62d28f4e2 100644 (file)
@@ -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));
@@ -998,6 +1000,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));
@@ -1092,8 +1095,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));
@@ -1204,6 +1209,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));
@@ -1267,9 +1273,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));
@@ -1301,6 +1310,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));
index 6908cbf78f349e8201d6c9dcfffeb90c2fec74cb..47bb6fcecc1ba652126e4934b63989ff7641e2f6 100644 (file)
@@ -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)
@@ -489,6 +491,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)
@@ -583,8 +586,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)
@@ -695,6 +700,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)
@@ -758,9 +764,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)
@@ -792,6 +801,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)
index da2ed7422c9deb7196f76a1d9e780502ef39f77a..70a54f5273e44654ccc18b0916d2c62a94e7abdd 100644 (file)
@@ -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), \
@@ -996,6 +998,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), \
@@ -1090,8 +1093,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), \
@@ -1202,6 +1207,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), \
@@ -1265,9 +1271,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), \
@@ -1299,6 +1308,7 @@ extern "C" {
     INIT_ID(wbits), \
     INIT_ID(week), \
     INIT_ID(weekday), \
+    INIT_ID(weeks), \
     INIT_ID(which), \
     INIT_ID(who), \
     INIT_ID(withdata), \
index b1f411945e7856e8c8a6803b537d3cd388e2fa07..89444f4fb83b94a35ff943baa3672bbbdb51ab34 100644 (file)
@@ -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));
@@ -1744,6 +1752,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));
@@ -2120,6 +2132,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));
@@ -2128,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(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));
@@ -2568,6 +2588,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));
@@ -2820,6 +2844,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));
@@ -2832,6 +2860,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));
@@ -2956,6 +2992,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));
index bc35823f70144eb1b5564e7ffd1c531cc32b129e..0955005df5ccee137c76866b5c82a27387714e27 100644 (file)
@@ -1083,7 +1083,7 @@ class date:
 
     @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 @@ date.resolution = timedelta(days=1)
 
 
 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 @@ class time:
 
     @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 @@ time.resolution = timedelta(microseconds=1)
 
 
 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 @@ class datetime(date):
 
     @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
index 3bd3a866570042b12ea2927e873d2c6967b4f5c7..4e42ae52765d0f0e9677417dd8bbd94c03d1e86f 100644 (file)
@@ -2147,14 +2147,20 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
             (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 @@ class TestDateTime(TestDate):
             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 @@ class TestDateTime(TestDate):
 
             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 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase):
             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 @@ class TZInfoBase:
                     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 @@ class TestTimeTZ(TestTime, TZInfoBase, unittest.TestCase):
 
             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 @@ class TestDateTimeTZ(TestDateTime, TZInfoBase, unittest.TestCase):
                 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)
 
index 30e01b8cd87a75475907d71cc98fd550080e26a2..c8c1a5226114b943a946b31df02153807a389481 100644 (file)
@@ -5831,6 +5831,21 @@ class TestSignatureDefinitions(unittest.TestCase):
         import collections.abc
         self._test_module_has_signatures(collections.abc)
 
+    def test_datetime_module_has_signatures(self):
+        # Only test if the C implementation is available.
+        import_helper.import_module('_datetime')
+        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 (file)
index 0000000..37f535f
--- /dev/null
@@ -0,0 +1,2 @@
+:meth:`datetime.date.fromisocalendar` can now raise OverflowError for out of
+range arguments.
index 3f7afbe27d735802f0ce16d778a12d0c3f7dd0aa..e0bd4993817277a165e01ba5c4842b9cd59666c8 100644 (file)
@@ -331,8 +331,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"
 
@@ -1171,19 +1173,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;
@@ -1235,7 +1236,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;
@@ -1261,7 +1262,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);
@@ -1271,10 +1272,10 @@ Done:
 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);
@@ -1291,7 +1292,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);
@@ -1340,10 +1341,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);
     }
@@ -2768,38 +2769,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;
@@ -2810,32 +2812,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) {
@@ -3034,13 +3036,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 */
@@ -3098,7 +3093,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 */
@@ -3174,8 +3169,6 @@ static PyGetSetDef date_getset[] = {
 
 /* Constructors. */
 
-static char *date_kws[] = {"year", "month", "day", NULL};
-
 static PyObject *
 date_from_pickle(PyTypeObject *type, PyObject *state)
 {
@@ -3193,11 +3186,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);
@@ -3223,22 +3211,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;
@@ -3260,8 +3262,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;
@@ -3275,7 +3287,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;
 }
@@ -3297,7 +3309,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,
@@ -3311,52 +3323,58 @@ datetime_date_fromtimestamp_capi(PyObject *cls, PyObject *args)
     PyObject *result = NULL;
 
     if (PyArg_UnpackTuple(args, "fromtimestamp", 1, 1, &timestamp)) {
-        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;
     }
@@ -3375,33 +3393,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);
 
@@ -3422,26 +3439,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;
 }
@@ -3465,8 +3490,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;
 }
 
@@ -3558,20 +3582,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)
@@ -3581,14 +3611,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);
@@ -3834,7 +3870,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
@@ -3895,38 +3931,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().")},
@@ -3961,9 +3978,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 */
@@ -3998,7 +4012,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 */
@@ -4201,7 +4215,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)
@@ -4245,18 +4260,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
@@ -4444,9 +4462,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 */
@@ -4468,7 +4483,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 */
@@ -4570,9 +4585,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)
 {
@@ -4608,17 +4620,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);
         }
@@ -4644,40 +4649,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;
 }
@@ -4756,17 +4788,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"},
@@ -4775,9 +4820,6 @@ time_isoformat(PyObject *op, PyObject *args, PyObject *kw)
     };
     size_t given_spec;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kw, "|s:isoformat", keywords, &timespec))
-        return NULL;
-
     if (timespec == NULL || strcmp(timespec, "auto") == 0) {
         if (us == 0) {
             /* seconds */
@@ -4823,18 +4865,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)
@@ -4855,6 +4901,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.
  */
@@ -5007,20 +5074,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;
@@ -5063,10 +5135,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);
     }
 
@@ -5078,7 +5150,7 @@ invalid_iso_midnight:
     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:
@@ -5114,21 +5186,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));
 }
 
@@ -5136,26 +5215,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).")},
@@ -5171,24 +5238,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 */
@@ -5209,8 +5264,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 */
@@ -5296,11 +5351,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)
 {
@@ -5336,20 +5386,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);
         }
@@ -5375,22 +5415,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
@@ -5447,7 +5511,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;
@@ -5519,7 +5583,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;
@@ -5537,7 +5601,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) {
@@ -5580,7 +5644,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);
@@ -5596,8 +5660,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 "
@@ -5606,25 +5678,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, &timestamp, &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,
@@ -5638,9 +5717,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, &timestamp, &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 "
@@ -5649,23 +5754,27 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args)
     {
         return NULL;
     }
-    PyObject *timestamp;
-    PyObject *result = NULL;
 
-    if (PyArg_ParseTuple(args, "O:utcfromtimestamp", &timestamp))
-        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) {
@@ -5673,42 +5782,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 *
@@ -5866,23 +5976,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;
     }
@@ -5970,7 +6083,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);
@@ -5983,7 +6096,7 @@ invalid_iso_midnight:
     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);
@@ -6060,7 +6173,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 *
@@ -6222,18 +6335,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"},
@@ -6242,9 +6375,6 @@ datetime_isoformat(PyObject *op, PyObject *args, PyObject *kw)
     };
     size_t given_spec;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kw, "|Cs:isoformat", keywords, &sep, &timespec))
-        return NULL;
-
     if (timespec == NULL || strcmp(timespec, "auto") == 0) {
         if (us == 0) {
             /* seconds */
@@ -6282,7 +6412,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;
     }
@@ -6412,8 +6542,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);
@@ -6537,7 +6666,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 *
@@ -6673,20 +6802,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;
@@ -6983,22 +7115,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));
 }
@@ -7008,31 +7147,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: */
 
@@ -7057,15 +7177,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).")},
@@ -7081,24 +7193,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 */
@@ -7132,8 +7233,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 */
@@ -7190,7 +7291,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,
index 18e6129fad8a89aa0c453279c82006540581630d..7c4bd5503ed56b4a57da4c0ff8cc8ae01ece8579 100644 (file)
@@ -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=<unrepresentable>)\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], &timespec_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=<unrepresentable>)\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], &timespec_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 @@ skip_optional_kwonly:
 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]*/