@@ -3471,10 +3471,15 @@ date_repr(PyDateTime_Date *self)
34713471}
34723472
34733473static PyObject *
3474- date_isoformat (PyDateTime_Date * self , PyObject * Py_UNUSED ( ignored ) )
3474+ date_isoformat (PyDateTime_Date * self , PyObject * args , PyObject * kw )
34753475{
3476- return PyUnicode_FromFormat ("%04d-%02d-%02d" ,
3477- GET_YEAR (self ), GET_MONTH (self ), GET_DAY (self ));
3476+ int basic = 0 ;
3477+ static char * keywords [] = {"basic" , NULL };
3478+ if (!PyArg_ParseTupleAndKeywords (args , kw , "|p:isoformat" , keywords , & basic )) {
3479+ return NULL ;
3480+ }
3481+ const char * format = basic ? "%04d%02d%02d" : "%04d-%02d-%02d" ;
3482+ return PyUnicode_FromFormat (format , GET_YEAR (self ), GET_MONTH (self ), GET_DAY (self ));
34783483}
34793484
34803485/* str() calls the appropriate isoformat() method. */
@@ -3868,8 +3873,9 @@ static PyMethodDef date_methods[] = {
38683873 PyDoc_STR ("Return a named tuple containing ISO year, week number, and "
38693874 "weekday." )},
38703875
3871- {"isoformat" , (PyCFunction )date_isoformat , METH_NOARGS ,
3872- PyDoc_STR ("Return string in ISO 8601 format, YYYY-MM-DD." )},
3876+ {"isoformat" , (PyCFunction )date_isoformat , METH_VARARGS | METH_KEYWORDS ,
3877+ PyDoc_STR ("Return string in ISO 8601 format, YYYY-MM-DD.\n"
3878+ "If basic is true, uses the basic format, YYYYMMDD." )},
38733879
38743880 {"isoweekday" , (PyCFunction )date_isoweekday , METH_NOARGS ,
38753881 PyDoc_STR ("Return the day of the week represented by the date.\n"
@@ -4654,20 +4660,33 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw)
46544660{
46554661 char buf [100 ];
46564662 const char * timespec = NULL ;
4657- static char * keywords [] = {"timespec" , NULL };
4663+ int basic = 0 ;
4664+ static char * keywords [] = {"timespec" , "basic" , NULL };
46584665 PyObject * result ;
46594666 int us = TIME_GET_MICROSECOND (self );
4660- static const char * specs [][2 ] = {
4667+ static const char * specs_extended [][2 ] = {
46614668 {"hours" , "%02d" },
46624669 {"minutes" , "%02d:%02d" },
46634670 {"seconds" , "%02d:%02d:%02d" },
46644671 {"milliseconds" , "%02d:%02d:%02d.%03d" },
46654672 {"microseconds" , "%02d:%02d:%02d.%06d" },
46664673 };
4667- size_t given_spec ;
4674+ static const char * specs_basic [][2 ] = {
4675+ {"hours" , "%02d" },
4676+ {"minutes" , "%02d%02d" },
4677+ {"seconds" , "%02d%02d%02d" },
4678+ {"milliseconds" , "%02d%02d%02d.%03d" },
4679+ {"microseconds" , "%02d%02d%02d.%06d" },
4680+ };
46684681
4669- if (!PyArg_ParseTupleAndKeywords (args , kw , "|s :isoformat" , keywords , & timespec ))
4682+ if (!PyArg_ParseTupleAndKeywords (args , kw , "|sp :isoformat" , keywords , & timespec , & basic )) {
46704683 return NULL ;
4684+ }
4685+
4686+ const char * (* specs )[2 ] = basic ? specs_basic : specs_extended ;
4687+ // due to array decaying, Py_ARRAY_LENGTH(specs) would return 0
4688+ size_t specs_count = basic ? Py_ARRAY_LENGTH (specs_basic ) : Py_ARRAY_LENGTH (specs_extended );
4689+ size_t given_spec ;
46714690
46724691 if (timespec == NULL || strcmp (timespec , "auto" ) == 0 ) {
46734692 if (us == 0 ) {
@@ -4680,7 +4699,7 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw)
46804699 }
46814700 }
46824701 else {
4683- for (given_spec = 0 ; given_spec < Py_ARRAY_LENGTH ( specs ) ; given_spec ++ ) {
4702+ for (given_spec = 0 ; given_spec < specs_count ; given_spec ++ ) {
46844703 if (strcmp (timespec , specs [given_spec ][0 ]) == 0 ) {
46854704 if (given_spec == 3 ) {
46864705 /* milliseconds */
@@ -4691,7 +4710,7 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw)
46914710 }
46924711 }
46934712
4694- if (given_spec == Py_ARRAY_LENGTH ( specs ) ) {
4713+ if (given_spec == specs_count ) {
46954714 PyErr_Format (PyExc_ValueError , "Unknown timespec value" );
46964715 return NULL ;
46974716 }
@@ -4705,8 +4724,8 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw)
47054724 return result ;
47064725
47074726 /* We need to append the UTC offset. */
4708- if ( format_utcoffset ( buf , sizeof ( buf ), ":" , self -> tzinfo ,
4709- Py_None ) < 0 ) {
4727+ const char * offset_sep = basic ? "" : ":" ;
4728+ if ( format_utcoffset ( buf , sizeof ( buf ), offset_sep , self -> tzinfo , Py_None ) < 0 ) {
47104729 Py_DECREF (result );
47114730 return NULL ;
47124731 }
@@ -5006,6 +5025,8 @@ static PyMethodDef time_methods[] = {
50065025 {"isoformat" , _PyCFunction_CAST (time_isoformat ), METH_VARARGS | METH_KEYWORDS ,
50075026 PyDoc_STR ("Return string in ISO 8601 format, [HH[:MM[:SS[.mmm[uuu]]]]]"
50085027 "[+HH:MM].\n\n"
5028+ "If basic is true, separators ':' are removed "
5029+ "from the output (e.g., HHMMSS).\n"
50095030 "The optional argument timespec specifies the number "
50105031 "of additional terms\nof the time to include. Valid "
50115032 "options are 'auto', 'hours', 'minutes',\n'seconds', "
@@ -6045,21 +6066,34 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
60456066{
60466067 int sep = 'T' ;
60476068 char * timespec = NULL ;
6048- static char * keywords [] = {"sep" , "timespec" , NULL };
6069+ int basic = 0 ;
6070+ static char * keywords [] = {"sep" , "timespec" , "basic" , NULL };
60496071 char buffer [100 ];
60506072 PyObject * result = NULL ;
60516073 int us = DATE_GET_MICROSECOND (self );
6052- static const char * specs [][2 ] = {
6074+ static const char * specs_extended [][2 ] = {
60536075 {"hours" , "%04d-%02d-%02d%c%02d" },
60546076 {"minutes" , "%04d-%02d-%02d%c%02d:%02d" },
60556077 {"seconds" , "%04d-%02d-%02d%c%02d:%02d:%02d" },
60566078 {"milliseconds" , "%04d-%02d-%02d%c%02d:%02d:%02d.%03d" },
60576079 {"microseconds" , "%04d-%02d-%02d%c%02d:%02d:%02d.%06d" },
60586080 };
6059- size_t given_spec ;
6081+ static const char * specs_basic [][2 ] = {
6082+ {"hours" , "%04d%02d%02d%c%02d" },
6083+ {"minutes" , "%04d%02d%02d%c%02d%02d" },
6084+ {"seconds" , "%04d%02d%02d%c%02d%02d%02d" },
6085+ {"milliseconds" , "%04d%02d%02d%c%02d%02d%02d.%03d" },
6086+ {"microseconds" , "%04d%02d%02d%c%02d%02d%02d.%06d" },
6087+ };
60606088
6061- if (!PyArg_ParseTupleAndKeywords (args , kw , "|Cs :isoformat" , keywords , & sep , & timespec ))
6089+ if (!PyArg_ParseTupleAndKeywords (args , kw , "|Csp :isoformat" , keywords , & sep , & timespec , & basic )) {
60626090 return NULL ;
6091+ }
6092+
6093+ const char * (* specs )[2 ] = basic ? specs_basic : specs_extended ;
6094+ // due to array decaying, Py_ARRAY_LENGTH(specs) would return 0
6095+ size_t specs_count = basic ? Py_ARRAY_LENGTH (specs_basic ) : Py_ARRAY_LENGTH (specs_extended );
6096+ size_t given_spec ;
60636097
60646098 if (timespec == NULL || strcmp (timespec , "auto" ) == 0 ) {
60656099 if (us == 0 ) {
@@ -6072,7 +6106,7 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
60726106 }
60736107 }
60746108 else {
6075- for (given_spec = 0 ; given_spec < Py_ARRAY_LENGTH ( specs ) ; given_spec ++ ) {
6109+ for (given_spec = 0 ; given_spec < specs_count ; given_spec ++ ) {
60766110 if (strcmp (timespec , specs [given_spec ][0 ]) == 0 ) {
60776111 if (given_spec == 3 ) {
60786112 us = us / 1000 ;
@@ -6082,7 +6116,7 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
60826116 }
60836117 }
60846118
6085- if (given_spec == Py_ARRAY_LENGTH ( specs ) ) {
6119+ if (given_spec == specs_count ) {
60866120 PyErr_Format (PyExc_ValueError , "Unknown timespec value" );
60876121 return NULL ;
60886122 }
@@ -6098,8 +6132,8 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
60986132 return result ;
60996133
61006134 /* We need to append the UTC offset. */
6101- if ( format_utcoffset ( buffer , sizeof ( buffer ), ":" , self -> tzinfo ,
6102- (PyObject * )self ) < 0 ) {
6135+ const char * offset_sep = basic ? "" : ":" ;
6136+ if ( format_utcoffset ( buffer , sizeof ( buffer ), offset_sep , self -> tzinfo , (PyObject * )self ) < 0 ) {
61036137 Py_DECREF (result );
61046138 return NULL ;
61056139 }
@@ -6863,9 +6897,11 @@ static PyMethodDef datetime_methods[] = {
68636897
68646898 {"isoformat" , _PyCFunction_CAST (datetime_isoformat ), METH_VARARGS | METH_KEYWORDS ,
68656899 PyDoc_STR ("[sep] -> string in ISO 8601 format, "
6866- "YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n"
6900+ "YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n\n "
68676901 "sep is used to separate the year from the time, and "
68686902 "defaults to 'T'.\n"
6903+ "If basic is true, separators ':' and '-' are removed "
6904+ "from the output (e.g., YYYYMMDDTHHMMSS).\n"
68696905 "The optional argument timespec specifies the number "
68706906 "of additional terms\nof the time to include. Valid "
68716907 "options are 'auto', 'hours', 'minutes',\n'seconds', "
0 commit comments