]> granicus.if.org Git - python/commitdiff
Y2K fix affecting asctime(), mktime(), strftime().
authorGuido van Rossum <guido@python.org>
Tue, 25 Aug 1998 14:51:12 +0000 (14:51 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 25 Aug 1998 14:51:12 +0000 (14:51 +0000)
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

index 7feefbcb26238ab57a5b201b4dd13f37eb6bbb89..7ad8a6fe2d9f989767df043f17935ede65be87fb 100644 (file)
@@ -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
        {