| Store | Cart

Re: [Python-Dev] Aware datetime from naive local time Was: Status on PEP-431 Timezones

From: Akira Li <4kir...@gmail.com>
Sat, 18 Apr 2015 03:19:41 +0300
On Thu, Apr 16, 2015 at 1:14 AM, Alexander Belopolsky <
alex...@gmail.com> wrote:

>> On Wed, Apr 15, 2015 at 4:46 PM, Akira Li <4kir...@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
Pyth...@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: https://mail.python.org/mailman/options/python-dev/python-dev-ml%40activestate.com

Recent Messages in this Thread
Alexander Belopolsky Apr 10, 2015 02:21 am
Alexander Belopolsky Apr 10, 2015 03:14 am
Nick Coghlan Apr 10, 2015 10:38 am
Alexander Belopolsky Apr 10, 2015 11:32 pm
Chris Barker Apr 13, 2015 05:24 pm
Alexander Belopolsky Apr 13, 2015 05:45 pm
Chris Barker Apr 13, 2015 06:05 pm
Alexander Belopolsky Apr 13, 2015 07:14 pm
MRAB Apr 13, 2015 08:10 pm
Chris Barker Apr 13, 2015 09:12 pm
Akira Li Apr 15, 2015 10:02 pm
Akira Li Apr 15, 2015 08:46 pm
Alexander Belopolsky Apr 15, 2015 10:14 pm
Akira Li Apr 18, 2015 12:19 am
Alexander Belopolsky Apr 18, 2015 01:10 am
Messages in this thread