.. function:: asctime([t])
Convert a tuple or :class:`struct_time` representing a time as returned by
- :func:`gmtime` or :func:`localtime` to a 24-character string of the following
+ :func:`gmtime` or :func:`localtime` to a string of the following
form: ``'Sun Jun 20 23:21:05 1993'``. If *t* is not provided, the current time
as returned by :func:`localtime` is used. Locale information is not used by
:func:`asctime`.
import time
import unittest
import locale
+import sysconfig
class TimeTestCase(unittest.TestCase):
def test_asctime(self):
time.asctime(time.gmtime(self.t))
+
+ # Max year is only limited by the size of C int.
+ sizeof_int = sysconfig.get_config_vars('SIZEOF_INT')[0]
+ bigyear = (1 << 8 * sizeof_int - 1) - 1
+ asc = time.asctime((bigyear, 6, 1) + (0,)*6)
+ self.assertEqual(asc[-len(str(bigyear)):], str(bigyear))
+ self.assertRaises(OverflowError, time.asctime, (bigyear + 1,) + (0,)*8)
self.assertRaises(TypeError, time.asctime, 0)
self.assertRaises(TypeError, time.asctime, ())
- # XXX: POSIX-compliant asctime should refuse to convert year > 9999,
- # but glibc implementation does not. For now, just check it doesn't
- # segfault as it did before, and the result contains no newline.
- try:
- result = time.asctime((12345, 1, 0, 0, 0, 0, 0, 0, 0))
- except ValueError:
- # for POSIX-compliant runtimes
- pass
- else:
- self.assertNotIn('\n', result)
def test_asctime_bounding_check(self):
self._bounds_checking(time.asctime)
def test_ctime(self):
- # XXX: POSIX-compliant ctime should refuse to convert year > 9999,
- # but glibc implementation does not. For now, just check it doesn't
- # segfault as it did before, and the result contains no newline.
+ t = time.mktime((1973, 9, 16, 1, 3, 52, 0, 0, -1))
+ self.assertEqual(time.ctime(t), 'Sun Sep 16 01:03:52 1973')
+ t = time.mktime((2000, 1, 1, 0, 0, 0, 0, 0, -1))
+ self.assertEqual(time.ctime(t), 'Sat Jan 1 00:00:00 2000')
try:
- result = time.ctime(1e12)
+ bigval = time.mktime((10000, 1, 10) + (0,)*6)
except ValueError:
- # for POSIX-compliant runtimes (or 32-bit systems, where time_t
- # cannot hold timestamps with a five-digit year)
+ # If mktime fails, ctime will fail too. This may happen
+ # on some platforms.
pass
else:
- self.assertNotIn('\n', result)
+ self.assertEquals(time.ctime(bigval)[-5:], '10000')
@unittest.skipIf(not hasattr(time, "tzset"),
"time module has no attribute tzset")
Extension Modules
-----------------
+- Issue #8013: time.asctime and time.ctime no longer call system
+ asctime and ctime functions. The year range for time.asctime is now
+ 1900 through maxint. The range for time.ctime is the same as for
+ time.localtime. The string produced by these functions is longer
+ than 24 characters when year is greater than 9999.
+
- Issue #6608: time.asctime is now checking struct tm fields its input
before passing it to the system asctime. Patch by MunSic Jeong.
return strptime_result;
}
+
PyDoc_STRVAR(strptime_doc,
"strptime(string, format) -> struct_time\n\
\n\
Parse a string to a time tuple according to a format specification.\n\
See the library reference manual for formatting codes (same as strftime()).");
+static PyObject *
+_asctime(struct tm *timeptr)
+{
+ /* Inspired by Open Group reference implementation available at
+ * http://pubs.opengroup.org/onlinepubs/009695399/functions/asctime.html */
+ static char wday_name[7][3] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+ static char mon_name[12][3] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ char buf[20]; /* 'Sun Sep 16 01:03:52\0' */
+ int n;
+
+ n = snprintf(buf, sizeof(buf), "%.3s %.3s%3d %.2d:%.2d:%.2d",
+ wday_name[timeptr->tm_wday],
+ mon_name[timeptr->tm_mon],
+ timeptr->tm_mday, timeptr->tm_hour,
+ timeptr->tm_min, timeptr->tm_sec);
+ /* XXX: since the fields used by snprintf above are validated in checktm,
+ * the following condition should never trigger. We keep the check because
+ * historically fixed size buffer used in asctime was the source of
+ * crashes. */
+ if (n + 1 != sizeof(buf)) {
+ PyErr_SetString(PyExc_ValueError, "unconvertible time");
+ return NULL;
+ }
+
+ return PyUnicode_FromFormat("%s %d", buf, 1900 + timeptr->tm_year);
+}
static PyObject *
time_asctime(PyObject *self, PyObject *args)
{
PyObject *tup = NULL;
struct tm buf;
- char *p, *q;
+
if (!PyArg_UnpackTuple(args, "asctime", 0, 1, &tup))
return NULL;
if (tup == NULL) {
buf = *localtime(&tt);
} else if (!gettmarg(tup, &buf) || !checktm(&buf))
return NULL;
- p = asctime(&buf);
- if (p == NULL) {
- PyErr_SetString(PyExc_ValueError, "unconvertible time");
- return NULL;
- }
- /* Replace a terminating newline by a null byte, normally at position 24.
- * It can occur later if the year has more than four digits. */
- for (q = p+24; *q != '\0'; q++)
- if (*q == '\n')
- *q = '\0';
- return PyUnicode_FromString(p);
+ return _asctime(&buf);
}
PyDoc_STRVAR(asctime_doc,
{
PyObject *ot = NULL;
time_t tt;
- char *p, *q;
+ struct tm *timeptr;
if (!PyArg_UnpackTuple(args, "ctime", 0, 1, &ot))
return NULL;
if (tt == (time_t)-1 && PyErr_Occurred())
return NULL;
}
- p = ctime(&tt);
- if (p == NULL) {
+ timeptr = localtime(&tt);
+ if (timeptr == NULL) {
PyErr_SetString(PyExc_ValueError, "unconvertible time");
- return NULL;
+ return NULL;
}
- /* Replace a terminating newline by a null byte, normally at position 24.
- * It can occur later if the year has more than four digits. */
- for (q = p+24; *q != '\0'; q++)
- if (*q == '\n')
- *q = '\0';
- return PyUnicode_FromString(p);
+ return _asctime(timeptr);
}
PyDoc_STRVAR(ctime_doc,