classification
Title: [2.7] time.asctime() regression
Type: Stage: resolved
Components: Library (Lib) Versions: Python 2.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: belopolsky, p-ganssle, vstinner, ztane
Priority: normal Keywords:

Created on 2018-12-12 10:43 by vstinner, last changed 2018-12-22 07:49 by ztane. This issue is now closed.

Messages (4)
msg331687 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2018-12-12 10:43
It seems like bpo-31339 introduced a regression with commit eeadf5fc231163ec97a8010754d9c995c7c14876 to fix a security issue.

Copy of of bencordova's comment from GitHub:
https://github.com/python/cpython/pull/3293#issuecomment-446378058

I'm new at commenting on this project so apologies if this is not the appropriate place to do so.

From what I can see (upgrading from python 2.7.13->2.7.15), the string format on line 648 of Modules/timemodule.c causes a different output from time.ctime() and time.asctime(t) for "days of the month < 10"

"%s %s%3d %.2d:%.2d:%.2d %d"

The "%3d" in this change removes the leading zero on the tm_mday but maintains a leading space.

Just looking for feedback on what the intention was and if this is a bug.

python 2.7.13:

>>> import time
>>> t = time.strptime("6 Dec 18", "%d %b %y")
>>> time.asctime(t)
'Thu Dec 06 00:00:00 2018'

python 2.7.15:

>>> import time
>>> t = time.strptime("6 Dec 18", "%d %b %y")
>>> time.asctime(t)
'Thu Dec  6 00:00:00 2018'

Note, the string with this change includes two spaces between "Dec" and "6" which also looks awkward.

Original Post:
https://github.com/python/cpython/commit/eeadf5fc231163ec97a8010754d9c995c7c14876#r31642310
msg331690 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2018-12-12 11:02
Even if behavior changes in minor Python release are not welcome, IMHO this one was justified and worth it. asctime() has a crappy API: it returns a pointer to a static buffer somewhere in the libc. asctime_r() is better, but it has an undefined behavior for year after 9999. The change has been made to fix a security issue when Python runs on musl (C library).

I suggest to close the issue as "not a bug". Use time.strftime() if you want a specific format.

On Python 2.7.13, the format depended on the C library. Now Python 2.7 and 3 always have the same output on all platforms (on any C library).


> It seems like bpo-31339 introduced a regression with commit eeadf5fc231163ec97a8010754d9c995c7c14876 to fix a security issue.

commit eeadf5fc231163ec97a8010754d9c995c7c14876
Author: Victor Stinner <victor.stinner@gmail.com>
Date:   Wed Sep 6 01:35:39 2017 +0200

    ...    
    Backport and adapt the _asctime() function from the master branch to
    not depend on the implementation of asctime() and ctime() from the
    external C library. This change fixes a bug when Python is run using
    the musl C library.
    ...


python 2.7.13: 'Thu Dec 06 00:00:00 2018'
python 2.7.15: 'Thu Dec  6 00:00:00 2018'
Python 3.7.1:  'Thu Dec  6 00:00:00 2018'

Python 2.7 and 3.7 now have exactly the same output.

This format seems to be consistent with asctime() format of glibc 2.28 on my Fedora 29:
---
#include <stdio.h>
#include <time.h>

int main()
{
    char *str;
    struct tm *tm;
    time_t t = 0;
    tm = gmtime(&t);
    str = asctime(tm);
    printf("%s", str);
    return 0;
}
---

Output:
---
Thu Jan  1 00:00:00 1970
---



The Python format comes from bpo-8013:

commit b9588b528a48302a4884d0500caec71f1c59280c
Author: Alexander Belopolsky <alexander.belopolsky@gmail.com>
Date:   Tue Jan 4 16:34:30 2011 +0000

    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.
...
+    char buf[20]; /* 'Sun Sep 16 01:03:52\0' */
...
+    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);
...


Discussions:

* https://mail.python.org/pipermail/python-dev/2011-January/107187.html
* https://bugs.python.org/issue8013#msg125281



> Note, the string with this change includes two spaces between "Dec" and "6" which also looks awkward.

If you want a specific format, I suggest you to use time.strftime(). You may have a look at the datetime module.


> Original Post:

Sorry, the correct URL is:
https://github.com/python/cpython/commit/eeadf5fc231163ec97a8010754d9c995c7c14876#r31642310
msg332035 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2018-12-18 00:53
The change is deliberate and is not a bug.
msg332332 - (view) Author: Antti Haapala (ztane) * Date: 2018-12-22 07:49
C11 specifies the format used by asctime as being exactly 

    "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",

which matches the *new* output with space padding, less the newline.

As always, Microsoft got it wrong: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/asctime-wasctime?view=vs-2017 - even if deliberately saying 1-31 instead of 01-31 in the table.
History
Date User Action Args
2018-12-22 07:49:40ztanesetnosy: + ztane
messages: + msg332332
2018-12-18 00:53:19vstinnersetstatus: open -> closed
resolution: not a bug
messages: + msg332035

stage: resolved
2018-12-12 11:02:49vstinnersetnosy: + belopolsky, p-ganssle
messages: + msg331690
2018-12-12 10:43:18vstinnercreate