[Python-Dev] Status on PEP-431 Timezones

Stuart Bishop stuart at stuartbishop.net
Fri Apr 10 14:27:38 CEST 2015


On 10 April 2015 at 17:12, Nick Coghlan <ncoghlan at gmail.com> wrote:

> On 9 Apr 2015 16:41, "Isaac Schwabacher" <ischwabacher at wisc.edu> wrote:
>
>> I'm suggesting an internal representation, not a user interface. The only
>> user-facing consequence of this internal representation would be exposing
>> the offset to datetime.replace() and as a field on the object. All of the
>> other interfaces that convert naive datetimes into aware datetimes would
>> still use the is_dst flag as specified in the PEP. The intention is to make
>> it easy to implement arithmetic and things like relative timedeltas.
>>
>> But looking at datetime.h, which seems to be willing to sacrifice
>> conceptual simplicity in order to pack a datetime into as few bytes in
>> memory as possible, it seems like whatever made that a good idea makes this
>> a bad one. :/

For the history here (at least as I recall it), the is_dst flag was
deliberately left out of the datetime class because this single bit
would have bumped the pickle size by a whole byte. At the time, the
primary use case was for storing timestamps in Zope2's ZODB database.
Soon after it became apparent to most people that naive timestamps and
web applications don't mix, making the optimization pointless since
the pickle size blew out anyway with people storing the timezone (and
this is also the reason pytz.utc takes pains to be the minimum sized
pickle). Its probably all rather silly in todays 64 bit world.


> The question of "store the DST flag" vs "store the offset" is essentially a
> data normalisation one - there's only a single bit of additional information
> actually needed (whether the time is DST or not in the annual hour of
> ambiguity), which can then be combined with the local time, the location and
> the zone info database to get the *actual* offset.

The dst flag must be stored in the datetime, either as a boolean or
encoded in the timezone structure. If you only have the offset, you
lose interoperability with the time module (and the standard IANA
zoneinfo library, posix etc., which it wraps). (dt +
timedelta(hours=1)).ctime() will give an incorrect answer when you
cross a DST transition.

> A question the PEP perhaps *should* consider is whether or not to offer an
> API allowing datetime objects to be built from a naive datetime, a fixed
> offset and a location, throwing NonExistentTimeError if the given date, time
> and offset doesn't match either the DST or non-DST times at that location.

I don't think you need a specific API, apart from being able to
construct a tzinfo using nothing but an offset (lots of people require
this for things like parsing email headers, which is why pytz has the
FixedOffset class).

datetime.now().astimezone(FixedOffset(-1200)).astimezone(timezone('Melbourne/Australia',
is_dst=None)


> P.S. The description of NonExistentTimeError in the PEP doesn't seem quite
> right, as it currently says it will only be thrown if "is_dst=None", which
> seems like a copy and paste error from the definition of AmbiguousTimeError.

The PEP is correct here. If you explicitly specify is_dst, you know
which side of the transition you are on and which offset to use. You
can calculate datetime(2000, 12, 31, 2, 0, 0, 0).astimezone(foo,
is_dst=False) using the non-DST offset and get an answer. It might not
have ever appeared on the clock on your wall, but it is better than a
punch in the face. If you want a punch in the face, is_dst=None
refuses to guess and you get the exception.

(Except for those cases where the timezone offset is changed without a
DST transition, but that is rare enough everyone pretends they don't
exist)

(Thanks Lennart!)


More information about the Python-Dev mailing list