On Thu, Apr 16, 2015 at 1:14 AM, Alexander Belopolsky < alexander.belopol...@gmail.com> wrote:
> > On Wed, Apr 15, 2015 at 4:46 PM, Akira Li <4kir4...@gmail.com> wrote: > >> > Look what happened on July 1, 1990. At 2 AM, the clocks in Ukraine were >> > moved back one hour. So times like 01:30 AM happened twice there on >> that >> > day. Let's see how Python handles this situation >> > >> > $ TZ=Europe/Kiev python3 >> >>>> from email.utils import localtime >> >>>> from datetime import datetime >> >>>> localtime(datetime(1990,7,1,1,30)).strftime('%c %z %Z') >> > 'Sun Jul 1 01:30:00 1990 +0400 MSD' >> > >> > So far so good, I've got the first of the two 01:30AM's. But what if I >> > want the other 01:30AM? Well, >> > >> >>>> localtime(datetime(1990,7,1,1,30), isdst=0).strftime('%c %z %Z') >> > 'Sun Jul 1 01:30:00 1990 +0300 EEST' >> > >> > gives me "the other 01:30AM", but it is counter-intuitive: I have to ask >> > for the standard (winter) time to get the daylight savings (summer) >> time. >> > >> >> It looks incorrect. Here's the corresponding pytz code: >> >> from datetime import datetime >> import pytz >> >> tz = pytz.timezone('Europe/Kiev') >> print(tz.localize(datetime(1990, 7, 1, 1, 30), >> is_dst=False).strftime('%c %z %Z')) >> # -> Sun Jul 1 01:30:00 1990 +0300 EEST >> print(tz.localize(datetime(1990, 7, 1, 1, 30), >> is_dst=True).strftime('%c %z %Z')) >> # -> Sun Jul 1 01:30:00 1990 +0400 MSD >> >> See also "Enhance support for end-of-DST-like ambiguous time" [1] >> >> [1] https://bugs.launchpad.net/pytz/+bug/1378150 >> >> `email.utils.localtime()` is broken: >> > > If you think there is a bug in email.utils.localtime - please open an > issue at <bugs.python.org>. > > Your question below suggests that you believe it is not a bug i.e., `email.utils.localtime()` is broken *by design* unless you think it is ok to ignore `+0400 MSD`. pytz works for me (I can get both `+0300 EEST` and `+0400 MSD`). I don't think `localtime()` can be fixed without the tz database. I don't know whether it should be fixed, let somebody else who can't use pytz to pioneer the issue. The purpose of the code example is to **inform** that `email.utils.localtime()` fails (it returns only +0300 EEST) in this case: >> from datetime import datetime >> from email.utils import localtime >> >> print(localtime(datetime(1990, 7, 1, 1, 30)).strftime('%c %z %Z')) >> # -> Sun Jul 1 01:30:00 1990 +0300 EEST >> print(localtime(datetime(1990, 7, 1, 1, 30), isdst=0).strftime('%c %z >> %Z')) >> # -> Sun Jul 1 01:30:00 1990 +0300 EEST >> print(localtime(datetime(1990, 7, 1, 1, 30), isdst=1).strftime('%c %z >> %Z')) >> # -> Sun Jul 1 01:30:00 1990 +0300 EEST >> print(localtime(datetime(1990, 7, 1, 1, 30), isdst=-1).strftime('%c %z >> %Z')) >> # -> Sun Jul 1 01:30:00 1990 +0300 EEST >> >> >> Versions: >> >> $ ./python -V >> Python 3.5.0a3+ >> $ dpkg -s tzdata | grep -i version >> Version: 2015b-0ubuntu0.14.04 >> >> > The uncertainty about how to deal with the repeated hour was the reason >> why >> > email.utils.localtime-like interface did not make it to the datetime >> > module. >> >> "repeated hour" (time jumps back) can be treated like a end-of-DST >> transition, to resolve ambiguities [1]. > > > I don't understand what you are complaining about. It is quite possible > that pytz uses is_dst flag differently from the way email.utils.localtime > uses isdst. > > I was not able to find a good description of what is_dst means in pytz, > but localtime's isdst is documented as follows: > > a positive or zero value for *isdst* causes localtime to > presume initially that summer time (for example, Daylight Saving Time) > is or is not (respectively) in effect for the specified time. > > Can you demonstrate that email.utils.localtime does not behave as > documented? > No need to be so defensive about it. *""repeated hour" (time jumps back) can be treated like a end-of-DST transition, to resolve ambiguities [1]."* is just a *an example* on how to fix the problem in the same way how it is done in pytz: >>> from datetime import datetime >>> import pytz >>> tz = pytz.timezone('Europe/Kiev') >>> after = tz.localize(datetime(1990, 7, 1, 1, 30), is_dst=False) >>> before = tz.localize(datetime(1990, 7, 1, 1, 30), is_dst=True) >>> before < after True >>> before datetime.datetime(1990, 7, 1, 1, 30, tzinfo=<DstTzInfo 'Europe/Kiev' MSD+4:00:00 DST>) >>> after datetime.datetime(1990, 7, 1, 1, 30, tzinfo=<DstTzInfo 'Europe/Kiev' EEST+3:00:00 DST>) >>> before.astimezone(pytz.utc) datetime.datetime(1990, 6, 30, 21, 30, tzinfo=<UTC>) >>> after.astimezone(pytz.utc) datetime.datetime(1990, 6, 30, 22, 30, tzinfo=<UTC>) >>> before.dst() datetime.timedelta(0, 3600) >>> after.dst() datetime.timedelta(0, 3600) >>> pytz.OLSON_VERSION '2015b' Here's "summer time" in both cases i.e., it is not *true* end-of-DST transition (that is why I've used the word *"like"* above). If we ignore ambiguous time that may occur more than twice then a boolean flag such as pytz's is_dst is *always* enough to resolve the ambiguity assuming we have access to the tz database. And yes, the example demonstrates that the behavior of pytz's is_dst and localtime()'s isdst is different. The example just shows that the current behavior of localtime() doesn't allow to get `+0400 DST` (on my system, see the software versions above) and how to get it (*adopt* the pytz behavior -- you need zoneinfo for that) i.e., the message is a problem and a possible solution -- no complains. [1] https://bugs.launchpad.net/pytz/+bug/1378150 -- Akira.
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com