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.
# 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)
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
+++ /dev/null
-:meth:`datetime.datetime.strftime` now 0-pads years with less than four digits for the format specifiers ``%Y`` and ``%G`` on Linux.
-Patch by Ben Hsing
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 */
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.
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;
}
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);
Py_XDECREF(colonzreplacement);
Py_XDECREF(Zreplacement);
Py_XDECREF(newfmt);
- Py_XDECREF(strftime);
return result;
}
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
[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 ncurses/ncursesw and panel/panelw
dnl NOTE: old curses is not detected.
dnl have_curses=[no, ncursesw, ncurses]
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 you want to enable internal statistics gathering. */
#undef Py_STATS