(original) (raw)
On Tue, Sep 22, 2015 at 11:11 AM, Tim Peters <tim.peters@gmail.com> wrote:
\[Nick Coghlan\]
...
\>>> dt ==
\>>> datetime.fromtimestamp(dt.astimezone(utc).astimezone(dt.tzinfo).timestamp())
...
\[Guido\]
>> That can't be right -- There is no way any fromtimestamp() call can return
\>> a time in the gap.
\[Alexander Belopolsky\]
> I don't think Nick said that.
\[Tim Peters\]
I do, except that he didn't ;-) Count the parens carefully.
The .astimezone() conversions in Nick's expression are a red herring. They don't change the value of the timestamp. That's the invariant Guido mentioned:
dt.timestamp() == dt.astimezone(utc).timestamp() == dt.astimezone(utc).astimezone(dt.tzinfo).timestamp()
Now, if dt is in its tzinfo gap, then
dt != datetime.fromtimestamp(dt.timestamp(), dt.tzinfo)
Instead, you get something like this:
datetime.fromtimestamp(dt.timestamp(), dt.tzinfo) == dt + (1 - 2\*dt.fold) \* gap
where gap is the size of the gap expressed as a timedelta (typically gap = timedelta(hours=1)). In words, when you ask for 2:40 AM, but the clock jumps from 01:59 AM to 03:00 AM, the round trip through timestamp gives you 03:40 AM if fold=0 and 01:40 AM if fold=1\. This rule is somewhat arbitrary, but it has many nice mathematical and "human" properties.
(There is an (imperfect) analogy with the roots of a quadratic equation here: when no real solutions exist, the two complex solutions are a ± i\*b and "nice to have" real values are a ± b.)