Skip to content

Commit

Permalink
pythongh-123681: Check the strftime() behavior at runtime instead of …
Browse files Browse the repository at this point in the history
…at the compile time

It is needed to support cross-compiling.
Remove macros Py_NORMALIZE_CENTURY and Py_STRFTIME_C99_SUPPORT.
  • Loading branch information
serhiy-storchaka committed Jan 3, 2025
1 parent 58e9f95 commit 0d17190
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 177 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Check the ``strftime()`` behavior at runtime instead of at the compile time
to support cross-compiling. Remove macros Py_NORMALIZE_CENTURY and
Py_STRFTIME_C99_SUPPORT.
50 changes: 39 additions & 11 deletions Modules/_datetimemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1740,6 +1740,42 @@ format_utcoffset(char *buf, size_t buflen, const char *sep,
return 0;
}

/* Check whether year with century should be normalized for strftime. */
inline static int
normalize_century(void)
{
static int _normalize_century = -1;
if (_normalize_century < 0) {
char year[5];
struct tm date = {
.tm_year = -1801,
.tm_mon = 0,
.tm_mday = 1
};
_normalize_century = (strftime(year, sizeof(year), "%Y", &date) &&
strcmp(year, "0099") != 0);
}
return _normalize_century;
}

/* Check whether C99-specific strftime specifiers are supported. */
inline static int
strftime_c99_support(void)
{
static int _strftime_c99_support = -1;
if (_strftime_c99_support < 0) {
char full_date[11];
struct tm date = {
.tm_year = 0,
.tm_mon = 0,
.tm_mday = 1
};
_strftime_c99_support = (strftime(full_date, sizeof(full_date), "%F", &date) &&
strcmp(full_date, "1900-01-01") == 0);
}
return _strftime_c99_support;
}

static PyObject *
make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg)
{
Expand Down Expand Up @@ -1910,12 +1946,9 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
}
replacement = freplacement;
}
#ifdef Py_NORMALIZE_CENTURY
else if (ch == 'Y' || ch == 'G'
#ifdef Py_STRFTIME_C99_SUPPORT
|| ch == 'F' || ch == 'C'
#endif
) {
else if (normalize_century() && (ch == 'Y' || ch == 'G' ||
(strftime_c99_support() && (ch == 'F' || ch == 'C'))))
{
/* 0-pad year with century as necessary */
PyObject *item = PySequence_GetItem(timetuple, 0);
if (item == NULL) {
Expand Down Expand Up @@ -1952,15 +1985,11 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
* +6 to accommodate dashes, 2-digit month and day for %F. */
char buf[SIZEOF_LONG * 5 / 2 + 2 + 6];
Py_ssize_t n = PyOS_snprintf(buf, sizeof(buf),
#ifdef Py_STRFTIME_C99_SUPPORT
ch == 'F' ? "%04ld-%%m-%%d" :
#endif
"%04ld", year_long);
#ifdef Py_STRFTIME_C99_SUPPORT
if (ch == 'C') {
n -= 2;
}
#endif
if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, end) < 0) {
goto Error;
}
Expand All @@ -1970,7 +1999,6 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
}
continue;
}
#endif
else {
/* percent followed by something else */
continue;
Expand Down
104 changes: 0 additions & 104 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 0 additions & 56 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -6644,62 +6644,6 @@ then
[Define if you have struct stat.st_mtimensec])
fi

AC_CACHE_CHECK([whether year with century should be normalized for strftime], [ac_cv_normalize_century], [
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <time.h>
#include <string.h>
int main(void)
{
char year[5];
struct tm date = {
.tm_year = -1801,
.tm_mon = 0,
.tm_mday = 1
};
if (strftime(year, sizeof(year), "%Y", &date) && !strcmp(year, "0099")) {
return 1;
}
return 0;
}
]])],
[ac_cv_normalize_century=yes],
[ac_cv_normalize_century=no],
[ac_cv_normalize_century=yes])])
if test "$ac_cv_normalize_century" = yes
then
AC_DEFINE([Py_NORMALIZE_CENTURY], [1],
[Define if year with century should be normalized for strftime.])
fi

AC_CACHE_CHECK([whether C99-specific strftime specifiers are supported], [ac_cv_strftime_c99_support], [
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <time.h>
#include <string.h>
int main(void)
{
char full_date[11];
struct tm date = {
.tm_year = 0,
.tm_mon = 0,
.tm_mday = 1
};
if (strftime(full_date, sizeof(full_date), "%F", &date) && !strcmp(full_date, "1900-01-01")) {
return 0;
}
return 1;
}
]])],
[ac_cv_strftime_c99_support=yes],
[ac_cv_strftime_c99_support=no],
[ac_cv_strftime_c99_support=no])])
if test "$ac_cv_strftime_c99_support" = yes
then
AC_DEFINE([Py_STRFTIME_C99_SUPPORT], [1],
[Define if C99-specific strftime specifiers are supported.])
fi

dnl check for ncursesw/ncurses and panelw/panel
dnl NOTE: old curses is not detected.
dnl have_curses=[no, yes]
Expand Down
6 changes: 0 additions & 6 deletions pyconfig.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -1706,18 +1706,12 @@
/* Defined if _Complex C type is available. */
#undef Py_HAVE_C_COMPLEX

/* Define if year with century should be normalized for strftime. */
#undef Py_NORMALIZE_CENTURY

/* Define if rl_startup_hook takes arguments */
#undef Py_RL_STARTUP_HOOK_TAKES_ARGS

/* Define if you want to enable internal statistics gathering. */
#undef Py_STATS

/* Define if C99-specific strftime specifiers are supported. */
#undef Py_STRFTIME_C99_SUPPORT

/* The version of SunOS/Solaris as reported by `uname -r' without the dot. */
#undef Py_SUNOS_VERSION

Expand Down

0 comments on commit 0d17190

Please sign in to comment.