Joshua J. Kugler wrote: > Or could I entitle this, "A Wrinkle in time.py," with apologies to Madeleine > L'Engle. Either I've found a bug (or rather room for improvement) in > time.py, or I *really* need a time module that doesn't assume so much.
I'd be inclined to use the datetime module to avoid certain underlying library assumptions. I originally tried to retrace your steps and make comments about what is going on, but the UNIX time API is so bizarre that it's better for me to suggest a few things instead. First of all, you managed to get things working nicely in a GMT/UTC environment. Sadly, the time module doesn't provide all the functions you'd need to work with UTC without such hacks as calling tzset, although I've been trying to refine some patches which do provide such functions - see this link for more details: https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1667546&group_id=5470 Although I suggested setting tm_isdst to zero previously, I'm more convinced now that it's quite difficult to do the right thing with such simple measures alone. Again, the time module doesn't provide access to timezone offsets on individual time structures in its current form, nor does it support the %z format option for strftime and strptime, although the patches mentioned above do provide it; both of these things provide the foundations to convert localtimes to UTC times and to convert back only when needed, a bit like the way you're supposed to work with Unicode and only produce specific textual encodings once you're finished. [...] Anyway, here are some suggestions: In your original test case (or problem), it looked like you were seeing a DST "boundary" which then made the times appear further apart than they actually were. Adjusting this test case for my timezone, I can reproduce the issue but then add the %z format option (see the patches) to demonstrate that with access to timezone offsets there's nothing really wrong: >>> nondst = time.mktime(time.strptime('2007-03-25 02:00:00', '%Y-%m-%d >>> %H:%M:%S')) >>> dst = time.mktime(time.strptime('2007-03-25 03:00:00', '%Y-%m-%d %H:%M:%S')) >>> time.strftime('%Y-%m-%d %H:%M:%S %z', time.localtime(nondst)) '2007-03-25 03:00:00 +0200' >>> time.strftime('%Y-%m-%d %H:%M:%S %z', time.localtime(dst)) '2007-03-25 03:00:00 +0200' Certainly, the localtime (with undecided timezone) of 2am on 25th March gets converted to the DST timezone, but we can be more specific and make informed guesses as to what happens: >>> nondst = time.mktime(time.strptime('2007-03-25 02:00:00 CET', '%Y-%m-%d >>> %H:%M:%S %Z')) >>> time.strftime('%Y-%m-%d %H:%M:%S %Z', time.localtime(nondst)) '2007-03-25 03:00:00 CEST' And trying with 1:59am gives us what we'd expect: >>> nondst = time.mktime(time.strptime('2007-03-25 01:59:00', '%Y-%m-%d >>> %H:%M:%S')) >>> time.strftime('%Y-%m-%d %H:%M:%S %Z', time.localtime(nondst)) '2007-03-25 01:59:00 CET' Now, we might like to avoid dealing with localtime altogether, and for such work I've introduced a function called mktimetz which attempts to use the timezone offset to calculate a time value which works with localtime and gmtime mostly without surprises - something which mktime doesn't guarantee. However, since strptime tends to sit on the fence and not assert any knowledge about DST, and since mktimetz depends on reliable timezone information, you do need to be careful about supplying vague information in the first place: >>> tz2am = time.mktimetz(time.strptime('2007-03-25 02:00:00', '%Y-%m-%d >>> %H:%M:%S')) >>> time.strftime('%Y-%m-%d %H:%M:%S %Z', time.localtime(tz2am)) '2007-03-25 05:00:00 CEST' (I can only speculate as to what happens here, but it really isn't worth too much consideration.) Here, you really need mktime instead, because it will probably make the right guesses about the presumed localtime given. However, if you indicate the timezone, the result will be better: >>> tz2am = time.mktimetz(time.strptime('2007-03-25 02:00:00 CET', '%Y-%m-%d >>> %H:%M:%S %Z')) >>> time.strftime('%Y-%m-%d %H:%M:%S %Z', time.localtime(tz2am)) '2007-03-25 03:00:00 CEST' >>> time.strftime('%Y-%m-%d %H:%M:%S %Z', time.gmtime(tz2am)) '2007-03-25 01:00:00 GMT' Here, an offset wouldn't be precise enough in the input (something like +0100) because it wouldn't tell strptime about DST. I could go on for a very long time about all this, and I've spent a very long time messing around with the different time functions. My personal opinion is that Python's time/datetime support needs a boost if only in terms of useful additional library endorsements and better documentation. Perhaps we just need to give the datetime module the support it deserves and treat the time module as legacy code. > In other news, setting time.tzname = ('GMT', 'GMT') does nothing. You have > to set the environment variable, then call tzset. Is there a rational for > this? Seems odd. It's the bizarre, even perverse way of the old UNIX time API. Various enhancements have come along to diminish the need for such hacks, but as you can imagine, they aren't fully standardised *and* universally adopted. Paul -- http://mail.python.org/mailman/listinfo/python-list