[Datetime-SIG] What's are the issues?

Tim Peters tim.peters at gmail.com
Wed Jul 29 17:40:51 CEST 2015


[Tim]
>> But, as the docs have always pointed out, it (specifically .fromutc(),
>> which is at the base of all relevant calculations) doesn't even try to
>> handle transitions due to _other_ causes.  The only other such cause
>> I'm aware of is when a timezone's _base_ offset from UTC changes (not
>> a temporary DST transition, the timezone's "standard" offset changes
>> permanently (meaning until someone decides to change it again)).

[Lennart]
> Wait, what?
>
> This will be handled in the exact same way as DST changes, and if this
> is incorrect, then reasonably, so is the DST handling.

Nope, that's mistaken on both counts, but it is technical.  What I
said is correct in all respects given the current code.  Note that how
time zone _conversions_ work has nothing to do with user-visible
arithmetic semantics.  .Timezone conversions aren't even a concept in
the "naive time" model, which latter is the model single-zone datetime
arithmetic follows.  Conversions and arithmetic have no conceptual
intersection in datetime.  Completely distinct issues.  I'm saying
that in four different ways because I've said all four before in other
messages, but never before all in a single message.  If I try all
possible ways of saying it, one of them is bound to get across
eventually ;-)

.astimezone() and .fromutc() do whatever they need to do to meet
_their_ contracts.  How arithmetic works is irrelevant to their
contracts:  they have to meet their contracts regardless of how
datetime arithmetic works, or even if user-visible datetime arithmetic
had not been implemented at all.

The default conversion implementations are strong enough to do the
best possible job in the absence of the missing "is or is not DST
intended?" flag.  That info is indispensable in a handful of cases, so
they have to guess in those cases.  If an is_dst-;like flag were
added, they would no longer need to guess in those cases.

However, this is only strong enough to handle DST transitions.  This
is basically because we can directly ask a tzinfo instance whether we
are or aren't in daylight time (.dst()), but can't directly ask it
whether the base UTC offset has _changed_.  Indeed, we can't even
directly ask a tzinfo subclass what the base offset _is_!  We can only
ask it what the _total_ UTC offset is (.utcoffset()) and what the
current DST adjustment is (.dst()) at specific points in time.

The current algorithm is very brief and efficient (although tedious to
prove correct!), but bought the latter at the cost of _assuming_ the
base UTC offset never changes over time.  Of course that's a
documented assumption.

> What is "incorrect" here is of course a matter of opinion.

As documented, time zone conversions mimic the destination zone's
local clock in the case of DST transitions:  some span of local times
"vanish" when local DST starts, and some span of local times are
repeated when local DST ends.  It mimics the destination's local time
reality.  My guess is that we agree that's "correct" (I know I believe
it - I'm guessing about you ;-) ).

> I think it's incorrect because it doesn't agree with reality, you have claimed
> that it is correct, in "as per design".

Again, how the conversion routines work have nothing to do with how
user-visible arithmetic works.  That's because (at the conceptual
design level) conversions have nothing to do with the "naive time"
model; conversions take place outside that model, just as, e.g.,
manually adjusting a mechanical wrist watch at DST transitions occurs
outside the watch's implementation of naive time.

> But then reasonably that goes for this case as well? The same thing
> happens, which is that depending on the transitions direction, you can
> either end up in a time that doesn't exist, or one that happens twice.

Which is how .fromutc() "should be" strengthened to work in cases
where the _base_ UTC offset changes.  The current implementation is
wholly oblivious to that possibility.

But it is reasonable to ask how important it is to strengthen
.fromutc().  The .fromutc() docs have always said:

"""
Most tzinfo subclasses should be able to inherit the default fromutc()
implementation without problems. It’s strong enough to handle
fixed-offset time zones, and time zones accounting for both standard
and daylight time, and the latter even if the DST transition times
differ in different years. An example of a time zone the default
fromutc() implementation may not handle correctly in all cases is one
where the standard offset (from UTC) depends on the specific date and
time passed, which can happen for political reasons. The default
implementations of astimezone() and fromutc() may not produce the
result you want if the result is one of the hours straddling the
moment the standard offset changes.
"""

and the .astimezone() docs have always said:

"""
Note that the default tzinfo.fromutc() method can be overridden in a
tzinfo subclass to affect the result returned by astimezone().
''""

and the .dst() docs have always said:

"""
An instance tz of a tzinfo subclass that models both standard and
daylight times must be consistent in this sense:

tz.utcoffset(dt) - tz.dst(dt)

must return the same result for every datetime dt with dt.tzinfo == tz
For sane tzinfo subclasses, this expression yields the time zone’s
“standard offset”, which should not depend on the date or the time,
but only on geographic location. The implementation of
datetime.astimezone() relies on this, but cannot detect violations;
it’s the programmer’s responsibility to ensure it. If a tzinfo
subclass cannot guarantee this, it may be able to override the default
implementation of tzinfo.fromutc() to work correctly with astimezone()
regardless.
"""

Have any of the later Python date-and-time packages bothered to
implement a stronger .fromutc()?  I don't know.  The potential
problems with base-offset-changing tzinfo subclasses have always been
documented, and I made .fromutc() a user-visible method precisely so
that it _could_ be overridden, and the docs have always explicitly
pointed that out  But if nobody has bothered to create a stronger
version after a dozen years ... well, everyone can draw their own
conclusions ;-)


More information about the Datetime-SIG mailing list