Index: Lib/test/test_time.py =================================================================== --- Lib/test/test_time.py (revision 54231) +++ Lib/test/test_time.py (working copy) @@ -218,6 +218,30 @@ t1 = time.mktime(lt1) self.assert_(0 <= (t1-t0) < 0.2) + def test_localtime_timezone(self): + # Get the localtime and examine it for the offset and zone. + lt = time.localtime() + self.assert_(hasattr(lt, "tm_gmtoff")) + self.assert_(hasattr(lt, "tm_zone")) + # See if the offset and zone are similar to the module + # attributes. + self.assert_(lt.tm_gmtoff is None and not hasattr(time, "timezone") or lt.tm_gmtoff == -time.timezone) + self.assert_(lt.tm_zone is None and not hasattr(time, "tzname") or lt.tm_zone == time.tzname[lt.tm_isdst]) + # Try and make UNIX times from the localtime and a 9-tuple + # created from the localtime. Test to see that the times are + # the same. + t = time.mktime(lt); t9 = time.mktime(lt[:9]) + self.assert_(t == t9) + # Make localtimes from the UNIX times and compare them to + # the original localtime, thus making a round trip. + new_lt = time.localtime(t); new_lt9 = time.localtime(t9) + self.assert_(new_lt == lt) + self.assert_(new_lt.tm_gmtoff is None and not hasattr(time, "timezone") or new_lt.tm_gmtoff == lt.tm_gmtoff) + self.assert_(new_lt.tm_zone is None and not hasattr(time, "tzname") or new_lt.tm_zone == lt.tm_zone) + self.assert_(new_lt9 == lt) + self.assert_(new_lt9.tm_gmtoff is None and not hasattr(time, "timezone") or new_lt.tm_gmtoff == lt.tm_gmtoff) + self.assert_(new_lt9.tm_zone is None and not hasattr(time, "tzname") or new_lt9.tm_zone == lt.tm_zone) + def test_main(): test_support.run_unittest(TimeTestCase) Index: Modules/timemodule.c =================================================================== --- Modules/timemodule.c (revision 54231) +++ Modules/timemodule.c (working copy) @@ -224,6 +224,8 @@ {"tm_wday", NULL}, {"tm_yday", NULL}, {"tm_isdst", NULL}, + {"tm_gmtoff", NULL}, + {"tm_zone", NULL}, {0} }; @@ -240,6 +242,9 @@ static PyObject * tmtotuple(struct tm *p) { +#ifndef HAVE_STRUCT_TM_TM_ZONE + PyObject *timezone, *tzname; +#endif PyObject *v = PyStructSequence_New(&StructTimeType); if (v == NULL) return NULL; @@ -255,6 +260,25 @@ SET(6, (p->tm_wday + 6) % 7); /* Want Monday == 0 */ SET(7, p->tm_yday + 1); /* Want January, 1 == 1 */ SET(8, p->tm_isdst); +#ifdef HAVE_STRUCT_TM_TM_ZONE + SET(9, p->tm_gmtoff); + PyStructSequence_SET_ITEM(v, 10, PyString_FromString(p->tm_zone)); +#else + timezone = PyDict_GetItemString(moddict, "timezone"); + if ((timezone != NULL) && PyInt_Check(timezone)) + PyStructSequence_SET_ITEM(v, 9, -PyInt_AsLong(timezone)); + else { + PyStructSequence_SET_ITEM(v, 9, Py_None); + Py_INCREF(Py_None); + } + tzname = PyDict_GetItemString(moddict, "tzname"); + if ((tzname != NULL) && PyTuple_Check(tzname)) + PyStructSequence_SET_ITEM(v, 10, PyTuple_GetItem(tzname, p->tm_isdst)); + else { + PyStructSequence_SET_ITEM(v, 10, Py_None); + Py_INCREF(Py_None); + } +#endif #undef SET if (PyErr_Occurred()) { Py_XDECREF(v); @@ -335,7 +359,16 @@ "localtime([seconds]) -> (tm_year,tm_mon,tm_day,tm_hour,tm_min,tm_sec,tm_wday,tm_yday,tm_isdst)\n\ \n\ Convert seconds since the Epoch to a time tuple expressing local time.\n\ -When 'seconds' is not passed in, convert the current time instead."); +When 'seconds' is not passed in, convert the current time instead.\n\ +\n\ +If time zone information is available, the tm_gmtoff and tm_zone\n\ +attributes may be consulted on the time tuple to obtain, respectively,\n\ +the location of the associated time zone in seconds east of GMT/UTC\n\ +and the name of the zone. Note that the value of tm_gmtoff may be\n\ +negative for time zones west of the prime meridian, for example.\n\ +\n\ +Where no time zone information is available, tm_gmtoff and tm_zone\n\ +will both be None."); static int gettmarg(PyObject *args, struct tm *p) @@ -354,6 +387,17 @@ &p->tm_yday, &p->tm_isdst)) return 0; +#ifdef HAVE_STRUCT_TM_TM_ZONE + /* Add GMT/UTC offset where a time structure is provided. */ + if (PyType_IsSubtype(args->ob_type, &StructTimeType)) { + PyObject *gmtoff = ((PyStructSequence *)(args))->ob_item[9]; + PyObject *zone = ((PyStructSequence *)(args))->ob_item[10]; + if (gmtoff != Py_None) + p->tm_gmtoff = PyInt_AsLong(gmtoff); + if (zone != Py_None) + p->tm_zone = PyString_AsString(zone); + } +#endif if (y < 1900) { PyObject *accept = PyDict_GetItemString(moddict, "accept2dyear");