gh-120713: Normalize year with century for datetime.strftime (GH-120820)

This commit is contained in:
blhsing 2024-06-29 14:32:42 +08:00 committed by GitHub
parent 92893fd8dc
commit 6d34938dc8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 174 additions and 16 deletions

View file

@ -1851,6 +1851,11 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
const char *ptoappend; /* ptr to string to append to output buffer */
Py_ssize_t ntoappend; /* # of bytes to append to output buffer */
#ifdef Py_NORMALIZE_CENTURY
/* Buffer of maximum size of formatted year permitted by long. */
char buf[SIZEOF_LONG*5/2+2];
#endif
assert(object && format && timetuple);
assert(PyUnicode_Check(format));
/* Convert the input format to a C string and size */
@ -1858,6 +1863,11 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
if (!pin)
return NULL;
PyObject *strftime = _PyImport_GetModuleAttrString("time", "strftime");
if (strftime == NULL) {
goto Done;
}
/* Scan the input format, looking for %z/%Z/%f escapes, building
* a new format. Since computing the replacements for those codes
* is expensive, don't unless they're actually used.
@ -1939,8 +1949,47 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
ptoappend = PyBytes_AS_STRING(freplacement);
ntoappend = PyBytes_GET_SIZE(freplacement);
}
#ifdef Py_NORMALIZE_CENTURY
else if (ch == 'Y' || ch == 'G') {
/* 0-pad year with century as necessary */
PyObject *item = PyTuple_GET_ITEM(timetuple, 0);
long year_long = PyLong_AsLong(item);
if (year_long == -1 && PyErr_Occurred()) {
goto Done;
}
/* Note that datetime(1000, 1, 1).strftime('%G') == '1000' so year
1000 for %G can go on the fast path. */
if (year_long >= 1000) {
goto PassThrough;
}
if (ch == 'G') {
PyObject *year_str = PyObject_CallFunction(strftime, "sO",
"%G", timetuple);
if (year_str == NULL) {
goto Done;
}
PyObject *year = PyNumber_Long(year_str);
Py_DECREF(year_str);
if (year == NULL) {
goto Done;
}
year_long = PyLong_AsLong(year);
Py_DECREF(year);
if (year_long == -1 && PyErr_Occurred()) {
goto Done;
}
}
ntoappend = PyOS_snprintf(buf, sizeof(buf), "%04ld", year_long);
ptoappend = buf;
}
#endif
else {
/* percent followed by something else */
#ifdef Py_NORMALIZE_CENTURY
PassThrough:
#endif
ptoappend = pin - 2;
ntoappend = 2;
}
@ -1972,17 +2021,13 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
goto Done;
{
PyObject *format;
PyObject *strftime = _PyImport_GetModuleAttrString("time", "strftime");
if (strftime == NULL)
goto Done;
format = PyUnicode_FromString(PyBytes_AS_STRING(newfmt));
if (format != NULL) {
result = PyObject_CallFunctionObjArgs(strftime,
format, timetuple, NULL);
Py_DECREF(format);
}
Py_DECREF(strftime);
}
Done:
Py_XDECREF(freplacement);
@ -1990,6 +2035,7 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
Py_XDECREF(colonzreplacement);
Py_XDECREF(Zreplacement);
Py_XDECREF(newfmt);
Py_XDECREF(strftime);
return result;
}