@@ -5846,218 +5846,6 @@ datetime_datetime_utcfromtimestamp_impl(PyTypeObject *type,
58465846 return datetime_from_timestamp (type , _PyTime_gmtime , timestamp , Py_None );
58475847}
58485848
5849- /* Locale-independent strptime parsing for _datetime.
5850- *
5851- * Return 1 for a complete numeric match, or 0 to use Lib/_strptime.py.
5852- * Parsing doesn't allocate or set exceptions. In particular, mismatches may
5853- * require regex backtracking, so their diagnostics belong to the fallback.
5854- */
5855-
5856- typedef struct {
5857- int year , month , day ;
5858- int hour , minute , second , fraction ;
5859- int gmtoff ; /* INT_MIN means no offset was supplied. */
5860- } StrptimeFields ;
5861-
5862- static int
5863- strptime_digits (const unsigned char * data , Py_ssize_t length , Py_ssize_t pos ,
5864- int minimum , int maximum , int * value )
5865- {
5866- int count = 0 ;
5867- * value = 0 ;
5868- while (count < maximum && pos + count < length ) {
5869- unsigned char c = data [pos + count ];
5870- if (c < '0' || c > '9' ) {
5871- break ;
5872- }
5873- * value = * value * 10 + c - '0' ;
5874- count ++ ;
5875- }
5876- return count >= minimum ? count : 0 ;
5877- }
5878-
5879- static int
5880- strptime_space (unsigned char c )
5881- {
5882- return c == ' ' || c == '\t' || c == '\n' || c == '\r' ||
5883- c == '\f' || c == '\v' ;
5884- }
5885-
5886- static int
5887- strptime_offset (const unsigned char * data , Py_ssize_t length , Py_ssize_t pos ,
5888- StrptimeFields * fields )
5889- {
5890- Py_ssize_t remaining = length - pos ;
5891- if (remaining == 0 ) {
5892- return 1 ;
5893- }
5894- if (remaining == 1 && data [pos ] == 'Z' ) {
5895- fields -> gmtoff = 0 ;
5896- return 1 ;
5897- }
5898- /* Offsets containing seconds or fractions use the Python parser. */
5899- if ((remaining != 5 && remaining != 6 ) ||
5900- (data [pos ] != '+' && data [pos ] != '-' )) {
5901- return 0 ;
5902- }
5903- int hours , minutes ;
5904- int colon = remaining == 6 ;
5905- if ((colon && data [pos + 3 ] != ':' ) ||
5906- strptime_digits (data , length , pos + 1 , 2 , 2 , & hours ) != 2 ||
5907- strptime_digits (data , length , pos + 3 + colon , 2 , 2 , & minutes ) != 2 ||
5908- hours > 23 || minutes > 59 ) {
5909- return 0 ;
5910- }
5911- fields -> gmtoff = (hours * 3600 + minutes * 60 ) *
5912- (data [pos ] == '-' ? -1 : 1 );
5913- return 1 ;
5914- }
5915-
5916- static int
5917- strptime_fields (PyObject * string , PyObject * format , StrptimeFields * fields )
5918- {
5919- /* String subclasses and non-ASCII input retain Python's behavior. */
5920- if (!PyUnicode_CheckExact (string ) || !PyUnicode_CheckExact (format ) ||
5921- !PyUnicode_IS_ASCII (string ) || !PyUnicode_IS_ASCII (format )) {
5922- return 0 ;
5923- }
5924- const unsigned char * data = PyUnicode_1BYTE_DATA (string );
5925- const unsigned char * fmt = PyUnicode_1BYTE_DATA (format );
5926- Py_ssize_t length = PyUnicode_GET_LENGTH (string );
5927- Py_ssize_t fmt_length = PyUnicode_GET_LENGTH (format );
5928- * fields = (StrptimeFields ){1900 , 1 , 1 , 0 , 0 , 0 , 0 , INT_MIN };
5929- unsigned int seen = 0 ;
5930- Py_ssize_t pos = 0 ;
5931-
5932- for (Py_ssize_t i = 0 ; i < fmt_length ; i ++ ) {
5933- unsigned char c = fmt [i ];
5934- if (strptime_space (c )) {
5935- if (pos == length || !strptime_space (data [pos ])) {
5936- return 0 ;
5937- }
5938- while (i + 1 < fmt_length && strptime_space (fmt [i + 1 ])) {
5939- i ++ ;
5940- }
5941- do {
5942- pos ++ ;
5943- } while (pos < length && strptime_space (data [pos ]));
5944- continue ;
5945- }
5946- if (c != '%' ) {
5947- if (pos == length || data [pos ++ ] != c ) {
5948- return 0 ;
5949- }
5950- continue ;
5951- }
5952- if (++ i == fmt_length ) {
5953- return 0 ;
5954- }
5955- c = fmt [i ];
5956- if (c == '%' ) {
5957- if (pos == length || data [pos ++ ] != '%' ) {
5958- return 0 ;
5959- }
5960- continue ;
5961- }
5962-
5963- /* Reject duplicate groups, aliases, and locale-dependent directives. */
5964- const char * directives = "YymdHMSfz" ;
5965- const char * directive = strchr (directives , c );
5966- if (directive == NULL || c == '\0' ) {
5967- return 0 ;
5968- }
5969- unsigned int bit = 1U << (directive - directives );
5970- if (seen & bit ) {
5971- return 0 ;
5972- }
5973- seen |= bit ;
5974-
5975- if (c == 'z' ) {
5976- if (i != fmt_length - 1 ||
5977- !strptime_offset (data , length , pos , fields )) {
5978- return 0 ;
5979- }
5980- pos = length ;
5981- continue ;
5982- }
5983-
5984- int minimum = 1 ;
5985- int maximum = 2 ;
5986- if (c == 'Y' ) {
5987- minimum = maximum = 4 ;
5988- }
5989- else if (c == 'y' ) {
5990- minimum = maximum = 2 ;
5991- }
5992- else if (c == 'f' ) {
5993- maximum = 6 ;
5994- }
5995- else if ((c == 'd' || c == 'H' ) && pos < length && data [pos ] == ' ' ) {
5996- pos ++ ;
5997- maximum = 1 ;
5998- }
5999- int value ;
6000- int count = strptime_digits (data , length , pos , minimum , maximum , & value );
6001- if (count == 0 ) {
6002- return 0 ;
6003- }
6004- pos += count ;
6005- switch (c ) {
6006- case 'Y' :
6007- fields -> year = value ;
6008- break ;
6009- case 'y' :
6010- fields -> year = value + (value <= 68 ? 2000 : 1900 );
6011- break ;
6012- case 'm' :
6013- if (value < 1 || value > 12 ) {
6014- return 0 ;
6015- }
6016- fields -> month = value ;
6017- break ;
6018- case 'd' :
6019- if (value < 1 || value > 31 ) {
6020- return 0 ;
6021- }
6022- fields -> day = value ;
6023- break ;
6024- case 'H' :
6025- if (value > 23 ) {
6026- return 0 ;
6027- }
6028- fields -> hour = value ;
6029- break ;
6030- case 'M' :
6031- if (value > 59 ) {
6032- return 0 ;
6033- }
6034- fields -> minute = value ;
6035- break ;
6036- case 'S' :
6037- if (value > 61 ) {
6038- return 0 ;
6039- }
6040- fields -> second = value ;
6041- break ;
6042- case 'f' :
6043- while (count ++ < 6 ) {
6044- value *= 10 ;
6045- }
6046- fields -> fraction = value ;
6047- break ;
6048- }
6049- }
6050- /* Mixed %Y/%y and day-without-year diagnostics belong to Python. */
6051- if (pos != length || (seen & 3 ) == 3 ||
6052- ((seen & (1U << 3 )) && !(seen & 3 )) ||
6053- fields -> year < 1 ||
6054- fields -> day > days_in_month (fields -> year , fields -> month )) {
6055- return 0 ;
6056- }
6057- return 1 ;
6058- }
6059-
6060-
60615849/*[clinic input]
60625850@permit_long_summary
60635851@classmethod
@@ -6079,9 +5867,9 @@ datetime_datetime_strptime_impl(PyTypeObject *type, PyObject *string,
60795867/*[clinic end generated code: output=af2c2d024f3203f5 input=ef7807589f1d50e7]*/
60805868{
60815869 /* Subclasses retain the Python parser's constructor arguments. */
6082- StrptimeFields fields ;
5870+ _PyTime_StrptimeFields fields ;
60835871 if (type == DATETIME_TYPE (NO_STATE ) &&
6084- strptime_fields (string , format , & fields )) {
5872+ _PyTime_Strptime (string , format , & fields )) {
60855873 PyObject * tzinfo = tzinfo_from_isoformat_results (
60865874 fields .gmtoff != INT_MIN , fields .gmtoff , 0 );
60875875 if (tzinfo == NULL ) {
0 commit comments