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

Alexander Belopolsky alexander.belopolsky at gmail.com
Fri Apr 10 05:14:10 CEST 2015


Sorry for a truncated message.  Please scroll past the quoted portion.

On Thu, Apr 9, 2015 at 10:21 PM, Alexander Belopolsky <
alexander.belopolsky at gmail.com> wrote:

>
> On Thu, Apr 9, 2015 at 4:51 PM, Isaac Schwabacher <ischwabacher at wisc.edu>
> wrote:
>
>> > > > Well, you are right, but at least we do have a localtime utility
>> hidden in the email package:
>> > > >
>> > > > >>> from datetime import *
>> > > > >>> from email.utils import localtime
>> > > > >>> print(localtime(datetime.now()))
>> > > > 2015-04-09 15:19:12.840000-04:00
>> > > >
>> > > > You can read <http://bugs.python.org/issue9527> for the reasons it
>> did not make into datetime.
>> > >
>> > > But that's restricted to the system time zone. Nothing good ever
>> comes from the system time zone...
>> >
>> > Let's solve one problem at a time. ...
>>
>> PEP 431 proposes to import zoneinfo into the stdlib, ...
>
>
> I am changing the subject so that we can focus on one question without
> diverting to PEP-size issues that are better suited for python ideas.
>
> I would like to add a functionality to the datetime module that would
> solve a seemingly simple problem: given a naive datetime instance assumed
> to be in local time, construct the corresponding aware datetime object with
> tzinfo set to an appropriate fixed offset datetime.timezone instance.
>
> Python 3 has this functionality implemented in the email package since
> version 3.3, and it appears to work well even
> in the ambiguous hour
>
> >>> from email.utils import localtime
> >>> from datetime import datetime
> >>> localtime(datetime(2014,11,2,1,30)).strftime('%c %z %Z')
> 'Sun Nov  2 01:30:00 2014 -0400 EDT'
> >>> localtime(datetime(2014,11,2,1,30), isdst=0).strftime('%c %z %Z')
> 'Sun Nov  2 01:30:00 2014 -0500 EST'
>
> However, in a location with a more interesting history, you can get a
> situation that
>

would look like this in the zoneinfo database:

$ zdump -v  -c 1992 Europe/Kiev
...
Europe/Kiev  Sat Mar 24 22:59:59 1990 UTC = Sun Mar 25 01:59:59 1990 MSK
isdst=0
Europe/Kiev  Sat Mar 24 23:00:00 1990 UTC = Sun Mar 25 03:00:00 1990 MSD
isdst=1
Europe/Kiev  Sat Jun 30 21:59:59 1990 UTC = Sun Jul  1 01:59:59 1990 MSD
isdst=1
Europe/Kiev  Sat Jun 30 22:00:00 1990 UTC = Sun Jul  1 01:00:00 1990 EEST
isdst=1
Europe/Kiev  Sat Sep 28 23:59:59 1991 UTC = Sun Sep 29 02:59:59 1991 EEST
isdst=1
Europe/Kiev  Sun Sep 29 00:00:00 1991 UTC = Sun Sep 29 02:00:00 1991 EET
isdst=0
...

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.

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.

The main objection to the isdst flag was that in most situations,
determining whether DST is in effect is as hard as finding the UTC offset,
so reducing the problem of finding the UTC offset to the one of finding the
value for isdst does not solve much.

I now realize that the problem is simply in the name for the flag.  While
we cannot often tell what isdst should be and in some situations the actual
DST status does not differentiate between the two possible times, we can
always say whether we want to get the first or the second time.

In other words, instead of localtime(dt, isdst=-1), we may want
 localtime(dt, which=0) where "which" is used to resolve the ambiguity:
"which=0" means return the first (in UTC order) of the two times and
"which=1" means return the second.  (In the non-ambiguous cases "which" is
ignored.)

An alternative solution would be make  localtime(dt) return a list of 0, 1
or 2 instances, but this will probably make a common usage (the case when
the user does not care which time she gets) more cumbersome.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20150409/a1d3b69f/attachment.html>


More information about the Python-Dev mailing list