Index: Lib/test/test_datetime.py =================================================================== --- Lib/test/test_datetime.py (revision 58132) +++ Lib/test/test_datetime.py (working copy) @@ -868,7 +868,7 @@ self.assertEqual(format(b, ''), str(dt)) for fmt in ["m:%m d:%d y:%y", - "m:%m d:%d y:%y H:%H M:%M S:%S", + "m:%m d:%d y:%y H:%H M:%M S:%S f:%f", "%z %Z", ]: self.assertEqual(format(dt, fmt), dt.strftime(fmt)) @@ -1195,7 +1195,7 @@ self.assertEqual(format(b, ''), str(dt)) for fmt in ["m:%m d:%d y:%y", - "m:%m d:%d y:%y H:%H M:%M S:%S", + "m:%m d:%d y:%y H:%H M:%M S:%S f:%f", "%z %Z", ]: self.assertEqual(format(dt, fmt), dt.strftime(fmt)) @@ -1556,9 +1556,9 @@ def test_more_strftime(self): # This tests fields beyond those tested by the TestDate.test_strftime. - t = self.theclass(2004, 12, 31, 6, 22, 33) - self.assertEqual(t.strftime("%m %d %y %S %M %H %j"), - "12 31 04 33 22 06 366") + t = self.theclass(2004, 12, 31, 6, 22, 33, 47) + self.assertEqual(t.strftime("%m %d %y %S %M %H %j %f"), + "12 31 04 33 22 06 366 000047") def test_extract(self): dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234) @@ -1831,7 +1831,7 @@ def test_strftime(self): t = self.theclass(1, 2, 3, 4) - self.assertEqual(t.strftime('%H %M %S'), "01 02 03") + self.assertEqual(t.strftime('%H %M %S %f'), "01 02 03 000004") # A naive object replaces %z and %Z with empty strings. self.assertEqual(t.strftime("'%z' '%Z'"), "'' ''") Index: Modules/datetimemodule.c =================================================================== --- Modules/datetimemodule.c (revision 58132) +++ Modules/datetimemodule.c (working copy) @@ -1177,10 +1177,24 @@ return NULL; } +static PyObject * +make_freplacement(PyObject *object) +{ + char freplacement[7]; + if (PyTime_Check(object)) + sprintf(freplacement, "%06d", TIME_GET_MICROSECOND(object)); + else if (PyDateTime_Check(object)) + sprintf(freplacement, "%06d", DATE_GET_MICROSECOND(object)); + else + sprintf(freplacement, "%06d", 0); + + return PyBytes_FromStringAndSize(freplacement, strlen(freplacement)); +} + /* I sure don't want to reproduce the strftime code from the time module, * so this imports the module and calls it. All the hair is due to - * giving special meanings to the %z and %Z format codes via a preprocessing - * step on the format string. + * giving special meanings to the %z, %Z and %f format codes via a + * preprocessing step on the format string. * tzinfoarg is the argument to pass to the object's tzinfo method, if * needed. */ @@ -1192,6 +1206,7 @@ PyObject *zreplacement = NULL; /* py string, replacement for %z */ PyObject *Zreplacement = NULL; /* py string, replacement for %Z */ + PyObject *freplacement = NULL; /* py string, replacement for %f */ const char *pin;/* pointer to next char in input format */ Py_ssize_t flen;/* length of input format */ @@ -1239,11 +1254,11 @@ } } - /* Scan the input format, looking for %z and %Z escapes, building + /* 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. */ - totalnew = flen + 1; /* realistic if no %z/%Z */ + totalnew = flen + 1; /* realistic if no %z/%Z/%f */ newfmt = PyBytes_FromStringAndSize(NULL, totalnew); if (newfmt == NULL) goto Done; pnew = PyBytes_AsString(newfmt); @@ -1301,6 +1316,18 @@ ptoappend = PyBytes_AS_STRING(Zreplacement); ntoappend = PyBytes_GET_SIZE(Zreplacement); } + else if (ch == 'f') { + /* format microseconds */ + if (freplacement == NULL) { + freplacement = make_freplacement(object); + if (freplacement == NULL) + goto Done; + } + assert(freplacement != NULL); + assert(PyBytes_Check(freplacement)); + ptoappend = PyBytes_AS_STRING(freplacement); + ntoappend = PyBytes_GET_SIZE(freplacement); + } else { /* percent followed by neither z nor Z */ ptoappend = pin - 2; @@ -1347,6 +1374,7 @@ Py_DECREF(time); } Done: + Py_XDECREF(freplacement); Py_XDECREF(zreplacement); Py_XDECREF(Zreplacement); Py_XDECREF(newfmt); @@ -3159,7 +3187,7 @@ { char buf[100]; PyObject *result; - int us = TIME_GET_MICROSECOND(self);; + int us = TIME_GET_MICROSECOND(self); if (us) result = PyUnicode_FromFormat("%02d:%02d:%02d.%06d", Index: Doc/library/datetime.rst =================================================================== --- Doc/library/datetime.rst (revision 58132) +++ Doc/library/datetime.rst (working copy) @@ -1294,10 +1294,16 @@ be used, as time objects have no such values. If they're used anyway, ``1900`` is substituted for the year, and ``0`` for the month and day. -For :class:`date` objects, the format codes for hours, minutes, and seconds -should not be used, as :class:`date` objects have no such values. If they're -used anyway, ``0`` is substituted for them. +For :class:`date` objects, the format codes for hours, minutes, seconds, and +fractions of sections should not be used, as :class:`date` objects have no +such values. If they're used anyway, ``0`` is substituted for them. +:class:`time` and :class:`datetime` objects support a ``%f`` format code +which expands to the number of microseconds in the object, zero-padded on +the left to six places. + +.. versionadded:: 2.6 + For a naive object, the ``%z`` and ``%Z`` format codes are replaced by empty strings.