[Datetime-SIG] Another round on error-checking

Tim Peters tim.peters at gmail.com
Thu Sep 3 02:39:41 CEST 2015

We should be clearer about something up front:  there are _two_
notions of "backward compatibility" here:

1. After PEP 495 is implemented but before any 495-compliant tzinfos exist.

2. After PEP 495 is implemented and the user explicitly employs a
495-compliant tzinfo.

There are few potential issues under #1, but - alas - not none, and -
double alas - none of them would be altered by any kind of flag or
inheritance pattern on tzinfos.

Under #1, no tzinfos know anything about `fold`, so little _could_
possibly change.  Users can explicitly set fold=1, and if so they
deserve whatever they get ;-)  But, as I read the PEP, there are 3
places Python may force fold=1 all on its own, all based on Python's
own (independent of any tzinfo) idea of the local timezone:

A. datetime.fromtimestamp() without a trzinfo argument.
B. datetime.now().
C. datetime.today()

[The PEP doesn't mention #C, but it probably should (it's defined to
be equivalent to passing time.time() to #A)]

Since none of these consult a tzinfo, they can start producing fold=1
immediately, and nothing can stop that.

So I take almost everything back ;-)

1. No trick with tzinfos can make a lick of difference to what A/B/C
will do from the start.

2. Because of #1, the idea of explicitly saying "I want a fold-aware
tzinfo" is the same thing as using a 495-compliant tzinfo.  Keep using
pre-495 tzinfos, and A/B/C remain your only worries.

But they're minor worries at worst, since in #1 no tzinfos pay any
attention to `fold` - the fundamental .utcoffset() in a pre-495 tzinfo
is oblivious to `fold`.

BTW, it may be useful to add a standardized (by the PEP) way for a
tzinfo to _say_ "I implement 495".  Like a magic new attribute.  Then
code that cares could use hasattr() to refuse or require using
495-compliant tzinfos.

> ...
> One reason to conflate with arithmetic is to limit the number of mental
> models people have to comprehend. If we conflate, there would be two
> models: "naive model" and "timeline model", and the choice between them
> would be controlled by one flag.
> I think that's already more than enough complexity for most people, but
> it's simplicity itself compared to the possibility that we could end up
> with three models: "naive model", "timeline model for conversions but
> still naive for arithmetic", and "timeline model".
> ISTM the second is too confusing and inconsistent in its view of the
> world to be featured as a primary mode; if someone really needs it, it'd
> be easy enough to write functions to do fast naive arithmetic on
> strict-aware datetimes (strip the tzinfo, then add it back). (The
> write-your-own-function argument can go both ways! ;)

It was always intended that users who wanted timeline arithmetic work
in UTC instead.  Everyone agrees that's best practice for many
reasons.  "Even Stuart" ;-) will agree with the latter.

As to using functions, they're not symmetric situations:  classic
arithmetic is very fast, so fast that the overheads of calling a
function and mucking around with stripping/reattaching tzinfos would
be a major speed hit.  timeline arithmetic is so slow that hardly
matters.  But work in UTC, as intended, and timeline arithmetic is the
same thing as classic arithmetic, so is also very fast when performed
the intended way.

> ...
> The fact that that even has to be a question illustrates how
> "timeline-mode conversions with fold disambiguation, but naive model for
> arithmetic" remains a problematic split-brain model that leads to
> inconsistencies.

I'm more inclined now to see it as an illustration that Alex's view is
right:  datetime +/- timedelta should indeed ignore fold.  If I wanted
timeline arithmetic, I should have been working in UTC from the start


>> I'm still to keen to push timeline arithmetic off to a later PEP.  It
>> doesn't have to be addressed to solve 495's problems.

> I think you've convincingly demonstrated in this thread that
> conversions, equality, comparisons, and arithmetic _are_ all
> fundamentally linked. If you try to cut them apart and handle some with
> a timeline model and some with a naive model, you'll have to violate a
> reasonably-expected invariant _somewhere_.

Python already did, using timeline arithmetic for cross-zone
subtraction and comparisons, and (necessarily so) for timezone
conversions, but classic arithmetic for all other intrazone
computations.  Mucking with that old model really does belong in a
different PEP.  We're having quite enough pain already just figuring
out what can go wrong with a single new bit ;-)

More information about the Datetime-SIG mailing list