]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Revert "[3.13] gh-120713: Normalize year with century for datetime.strftime (GH-12082...
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 29 Jul 2024 18:55:28 +0000 (21:55 +0300)
committerGitHub <noreply@github.com>
Mon, 29 Jul 2024 18:55:28 +0000 (21:55 +0300)
This reverts commit 009618f1125838af3c4afc772f2593637766fd45.

Lib/_pydatetime.py
Lib/test/datetimetester.py
Modules/_datetimemodule.c
configure
configure.ac
pyconfig.h.in

index 27cacb8e01ff3b676976050032c40d71bcaa8c50..34ccb2da13d0f31ac197e8d7b634b002456d4b20 100644 (file)
@@ -204,17 +204,6 @@ def _format_offset(off, sep=':'):
                 s += '.%06d' % ss.microseconds
     return s
 
-_normalize_century = None
-def _need_normalize_century():
-    global _normalize_century
-    if _normalize_century is None:
-        try:
-            _normalize_century = (
-                _time.strftime("%Y", (99, 1, 1, 0, 0, 0, 0, 1, 0)) != "0099")
-        except ValueError:
-            _normalize_century = True
-    return _normalize_century
-
 # Correctly substitute for %z and %Z escapes in strftime formats.
 def _wrap_strftime(object, format, timetuple):
     # Don't call utcoffset() or tzname() unless actually needed.
@@ -272,14 +261,6 @@ def _wrap_strftime(object, format, timetuple):
                                 # strftime is going to have at this: escape %
                                 Zreplace = s.replace('%', '%%')
                     newformat.append(Zreplace)
-                elif ch in 'YG' and object.year < 1000 and _need_normalize_century():
-                    # Note that datetime(1000, 1, 1).strftime('%G') == '1000' so
-                    # year 1000 for %G can go on the fast path.
-                    if ch == 'G':
-                        year = int(_time.strftime("%G", timetuple))
-                    else:
-                        year = object.year
-                    push('{:04}'.format(year))
                 else:
                     push('%')
                     push(ch)
index ca804fe28b32247b17d2be595a2be0434271e9c2..d0ee974dbcd15307a0ea1a86298fa740bb17365b 100644 (file)
@@ -1697,26 +1697,18 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
         self.assertTrue(self.theclass.max)
 
     def test_strftime_y2k(self):
-        # Test that years less than 1000 are 0-padded; note that the beginning
-        # of an ISO 8601 year may fall in an ISO week of the year before, and
-        # therefore needs an offset of -1 when formatting with '%G'.
-        dataset = (
-            (1, 0),
-            (49, -1),
-            (70, 0),
-            (99, 0),
-            (100, -1),
-            (999, 0),
-            (1000, 0),
-            (1970, 0),
-        )
-        for year, offset in dataset:
-            for specifier in 'YG':
-                with self.subTest(year=year, specifier=specifier):
-                    d = self.theclass(year, 1, 1)
-                    if specifier == 'G':
-                        year += offset
-                    self.assertEqual(d.strftime(f"%{specifier}"), f"{year:04d}")
+        for y in (1, 49, 70, 99, 100, 999, 1000, 1970):
+            d = self.theclass(y, 1, 1)
+            # Issue 13305:  For years < 1000, the value is not always
+            # padded to 4 digits across platforms.  The C standard
+            # assumes year >= 1900, so it does not specify the number
+            # of digits.
+            if d.strftime("%Y") != '%04d' % y:
+                # Year 42 returns '42', not padded
+                self.assertEqual(d.strftime("%Y"), '%d' % y)
+                # '0042' is obtained anyway
+                if support.has_strftime_extensions:
+                    self.assertEqual(d.strftime("%4Y"), '%04d' % y)
 
     def test_replace(self):
         cls = self.theclass
index 18631195a291c489de2944493e98725d46f525ff..4706a93bd158d298eef8ceb0169cb5bd165caa23 100644 (file)
@@ -1848,11 +1848,6 @@ 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 */
@@ -1860,11 +1855,6 @@ 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.
@@ -1946,47 +1936,8 @@ 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;
         }
@@ -2018,13 +1969,17 @@ 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);
@@ -2032,7 +1987,6 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
     Py_XDECREF(colonzreplacement);
     Py_XDECREF(Zreplacement);
     Py_XDECREF(newfmt);
-    Py_XDECREF(strftime);
     return result;
 }
 
index dcca9612f26a3d79dc5a8567201c78e628949a9f..beffc1fd76c790cd7311d6fb5dbba9cd856e8983 100755 (executable)
--- a/configure
+++ b/configure
@@ -25925,58 +25925,6 @@ printf "%s\n" "#define HAVE_STAT_TV_NSEC2 1" >>confdefs.h
 
 fi
 
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether year with century should be normalized for strftime" >&5
-printf %s "checking whether year with century should be normalized for strftime... " >&6; }
-if test ${ac_cv_normalize_century+y}
-then :
-  printf %s "(cached) " >&6
-else $as_nop
-
-if test "$cross_compiling" = yes
-then :
-  ac_cv_normalize_century=yes
-else $as_nop
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-#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;
-}
-
-_ACEOF
-if ac_fn_c_try_run "$LINENO"
-then :
-  ac_cv_normalize_century=yes
-else $as_nop
-  ac_cv_normalize_century=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-  conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_normalize_century" >&5
-printf "%s\n" "$ac_cv_normalize_century" >&6; }
-if test "$ac_cv_normalize_century" = yes
-then
-
-printf "%s\n" "#define Py_NORMALIZE_CENTURY 1" >>confdefs.h
-
-fi
-
 have_curses=no
 have_panel=no
 
index 1459a3ce62c787c89b33f64163e5b1e6e0626fd3..5842bd24c454e963a2f3d52857ae79e3308ce567 100644 (file)
@@ -6612,34 +6612,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
-
 dnl check for ncursesw/ncurses and panelw/panel
 dnl NOTE: old curses is not detected.
 dnl have_curses=[no, yes]
index 10980c92176a7e0bc68f591e2d6770150c1fd2f7..4d8b1d4f25440af9523e53730456a77e7b3dad06 100644 (file)
    SipHash13: 3, externally defined: 0 */
 #undef Py_HASH_ALGORITHM
 
-/* 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