[Datetime-SIG] Another approach to 495's glitches

Tim Peters tim.peters at gmail.com
Mon Sep 7 03:05:41 CEST 2015

```[Tim]
>> ...
>> Which obviously ;-) suggests yet another, possibly cleaner, approach:
>> have interzone subtraction,  and all interzone comparisons, _also_
>> force fold to 0 (instead of having only interzone __eq__ and __ne__
>> special-case fold=1) .

[Alex]
> I would not go that far.  While interzone subtraction between arbitrary
> zones is a rarely needed overkill, I find it useful to have subtraction work
> between a local zone and UTC.

Have you done so already in real life, or did it just occur to you
that you _could_ find it useful?

> For me, subtraction in this case is similar to conversion.  Fix the EPOCH
> and d = t - EPOCH together with t = EPOCH + d gives you a bijection between
> times and timedeltas.

Well, not without more words to clarify which operations are intended.
For example, it's impossible to tell what "-" means there unless you
spell out whether you're using classic or timeline arithmetic.  In
order to make your final claim true, I have to (I believe)
reverse-engineer that the claim is restricted to naive EPOCH and `d`,
or aware datetimes in a common fixed-offset zone. Otherwise your "-"
uses timeline arithmetic and your "+" classic arithmetic, and they're
different kinds of arithmetic in a non-fixed-offset zone.

> From that, you are one step away from various numeric time scales.
>  For example (t - datetime(1, 1, 1, tzinfo=timezone.utc)) // timedelta.resolution will
> give you a bijection between datetimes and some range of integers.

In this case the ambiguity is whether, by `datetimes`, you mean `t`
represents points in t.tzinfo's civil time, or points in a
tzinfo-annotated naive time.  I have to believe you mean the former,
because converting to UTC irretrievably loses tzinfo-annotated naive
times that correspond to "gap times" in that tzinfo's civil time
(i.e., this code doesn't give a bijection of tzinfo-annotated naive
datetimes if there are gaps in the tzinfo's civil time:  more than one
naive time can map to the same UTC time then, and so also to the same
integer then).

Replacing `t` with t.astimezone(utc) would make that obvious instead
of a puzzle, making it utterly clear that you only have civil time in
mind.  All instances of by-magic timeline arithmetic are an
"attractive nuisance" in datetime's current design :-(

> Thus if we are going to "sell" fold as a way to implement conversions that
> "always work", I think we should include these types of conversions as well.

Unfortunately, I have to suspect _someone_ out there already has this
kind of code, wrong-headed ;-) as it is.

So that kills that.

Unfortunately, that leaves the "special-case fold=1 in __eq__ and
__ne__" idea violating enough formal properties in interzone
arithmetic, albeit in rare cases, that I expect the best we can hope
for this PEP is "grudging acceptance".

I'll have to go back and read the "how about an insanely delicate
hash() implementation instead?" messages again ;-)
```