From cfbaecc5468030bb3f17dbeb9e7afa1bf3363920 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 25 Aug 1998 14:51:12 +0000 Subject: Y2K fix affecting asctime(), mktime(), strftime(). 2-digit years are now converted using rules that are (according to Fredrik Lundh) recommended by POSIX or X/Open: 0-68 mean 2000-2068, 69-99 mean 1969-1999. 2-digit years are now only accepted if time.accept2dyear is set to a nonzero integer; if it is zero or not an integer or absent, only year values >= 1900 are accepted. Year values 100-1899 and negative year values are never accepted. The initial value of time.accept2dyear depends on the environment variable PYTHONY2K: if PYTHONY2K is set and non-empty, time.accept2dyear is initialized to 0; if PYTHONY2K is empty or not set, time.accept2dyear is initialized to 0. --- Modules/timemodule.c | 56 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 7feefbc..7ad8a6f 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -112,6 +112,9 @@ extern int ftime(); static int floatsleep Py_PROTO((double)); static double floattime Py_PROTO(()); +/* For Y2K check */ +static PyObject *moddict; + #ifdef macintosh /* Our own timezone. We have enough information to deduce whether ** DST is on currently, but unfortunately we cannot put it to good @@ -322,8 +325,11 @@ gettmarg(args, p) PyObject *args; struct tm *p; { + int y; + memset((ANY *) p, '\0', sizeof(struct tm)); + if (!PyArg_Parse(args, "(iiiiiiiii)", - &p->tm_year, + &y, &p->tm_mon, &p->tm_mday, &p->tm_hour, @@ -333,8 +339,26 @@ gettmarg(args, p) &p->tm_yday, &p->tm_isdst)) return 0; - if (p->tm_year >= 1900) - p->tm_year -= 1900; + if (y < 1900) { + PyObject *accept = PyDict_GetItemString(moddict, + "accept2dyear"); + if (accept == NULL || !PyInt_Check(accept) || + PyInt_AsLong(accept) == 0) { + PyErr_SetString(PyExc_ValueError, + "year >= 1900 required"); + return 0; + } + if (69 <= y && y <= 99) + y += 1900; + else if (0 <= y && y <= 68) + y += 2000; + else { + PyErr_SetString(PyExc_ValueError, + "year out of range (00-99, 1900-*)"); + return 0; + } + } + p->tm_year = y - 1900; p->tm_mon--; p->tm_wday = (p->tm_wday + 1) % 7; p->tm_yday--; @@ -347,6 +371,7 @@ time_strftime(self, args) PyObject *self; PyObject *args; { + PyObject *tup; struct tm buf; const char *fmt; char *outbuf = 0; @@ -354,23 +379,8 @@ time_strftime(self, args) memset((ANY *) &buf, '\0', sizeof(buf)); - if (!PyArg_ParseTuple(args, "s(iiiiiiiii)", - &fmt, - &(buf.tm_year), - &(buf.tm_mon), - &(buf.tm_mday), - &(buf.tm_hour), - &(buf.tm_min), - &(buf.tm_sec), - &(buf.tm_wday), - &(buf.tm_yday), - &(buf.tm_isdst))) + if (!PyArg_ParseTuple(args, "sO", &fmt, &tup) || !gettmarg(tup, &buf)) return NULL; - if (buf.tm_year >= 1900) - buf.tm_year -= 1900; - buf.tm_mon--; - buf.tm_wday = (buf.tm_wday + 1) % 7; - buf.tm_yday--; /* I hate these functions that presume you know how big the output * will be ahead of time... */ @@ -414,6 +424,7 @@ time_strptime(self, args) PyErr_SetString(PyExc_ValueError, "invalid argument"); return NULL; } + memset((ANY *) &tm, '\0', sizeof(tm)); s = strptime(buf, fmt, &tm); if (s == NULL) { PyErr_SetString(PyExc_ValueError, "format mismatch"); @@ -595,6 +606,7 @@ void inittime() { PyObject *m, *d; + char *p; m = Py_InitModule3("time", time_methods, module_doc); d = PyModule_GetDict(m); #ifdef HAVE_TZNAME @@ -607,6 +619,12 @@ inittime() #endif ins(d, "daylight", PyInt_FromLong((long)daylight)); ins(d, "tzname", Py_BuildValue("(zz)", tzname[0], tzname[1])); + /* Accept 2-digit dates unless PYTHONY2K is set and non-empty */ + p = getenv("PYTHONY2K"); + ins(d, "accept2dyear", PyInt_FromLong((long) (!p || !*p))); + /* Squirrel away the module's dictionary for the y2k check */ + Py_INCREF(d); + moddict = d; #else /* !HAVE_TZNAME */ #if HAVE_TM_ZONE { -- cgit v0.12