[Python-Dev] Status on PEP-431 Timezones

Tim Peters tim.peters at gmail.com
Tue Jul 28 08:11:35 CEST 2015


[Tim]
>> timedelta objects only store days, seconds, and microseconds,

[Lennart Regebro <regebro at gmail.com>]
> Except that they don't actually store days. They store 24 hour
> periods,

Not really.  A timedelta is truly an integer number of microseconds,
and that's all.  The internal division into days, seconds and
microseconds is a mixed-radix scheme designed to make extracting some
common units of duration more efficient than by using division on a
single long integer all the time.  That's an implementation detail,
although one that is exposed.

> which, because of timezones changing, is not the same thing.

24 hours is 24 hours at any time in _any_ time zone, ignoring leap
seconds.  timedeltas are durations, not points in time.  "time zones"
make no sense applied to durations.

> This is also clearly intended, for example timedelta allows floats,
> and will convert the fraction into seconds.

I suspect I'm missing your meaning here.  Have a specific example to
illustrate it?  For example, are you talking about things like this?

>>> timedelta(weeks=0.5)
datetime.timedelta(3, 43200)

If so, what of it?  A week is _defined_ to be 7 days in timedelta,
where a day is in turn defined to be 24 hours, where ... until you
finally get down to microseconds.  None of this has anything to do
with points in time or time zones.  It's entirely about duration.  In
the example, a week turns out to be 604800000000 microseconds.  Half
of that is 302400000000 microseconds.  Convert that into mixed-radix
days-seconds-microseconds representation, and you're left with 3 days
and 43200 seconds (with 0 microseconds left over).  I don't see
anything remarkable about any of that - perhaps you just object to the
use of the _word_ "day" in this context?  It's just a word, and
there's nothing remarkable either about viewing a duration of "a day"
as being a duration of "24 hours".  It's a timedelta - a duration.
UTC offsets of any kind have nothing to do with pure durations, they
only have to do with points in time.  Calling "a day" 24 hours _in the
context_ of a timedelta is not only unobjectionable, calling a day
anything else in this entirely zone-free context would be insane ;-)

> And as you have repeated many times now, the datetime module's
> arithmetic is "naive"

But only when staying within a single time zone.  For example, if dt1
and dt2 have different tzinfo members, dt1 - dt2 acts as if both were
converted to UTC first before doing subtraction.  "Naive time" doesn't
come into play _across_ time zones, only _within_ a time zone.  When
mixing time zones, there's no plausible justification for ignoring
either of 'em.  So they're not ignored then.

> ie, it assumes that one day is always 24 hours.

That's really not what it's doing, although the analogy is sometimes
used in explanations.  What somedatetime+timedelta really does is
simpler than that:  it adds the number of microseconds represented by
the timedelta to somedatetime, being careful with carries across the
assorted time and date components.  That's all.  There are no
assumptions about what any of it "means".  What it _doesn't_ do is
consult the tzinfo member about anything, and _that's_ the true source
of your complaints.  It so happens that, yes, naive datetime
arithmetic does always treat "a day" as 24 hours (and "a week" as 7
days, and "a minute" as 60 seconds, and so on), but not really because
it's assuming anything about what days, weeks, etc "mean".  It's
working with microseconds, and it's giving the result you'd get from
working on somedatetime.replace(tzinfo=None) instead, except it
doesn't actually remove the tzinfo member.

> The problem with that assumption is that it isn't true.

There isn't really an assumption here.  "Naive time" has no concept of
"time zone", which isn't "an assumption" so much as a _requirement_ of
the design.  You can legitimately object that this requirement is at
odds with reality in some cases.  And that's true:  it is.  But that's
also been known since the start.  It's _intentionally_ at odds with
reality in some cases, because it was believed that a simpler
approximation to reality would be most useful most often to most
applications and programmers.  And you've heard from some of them
here.

Note that the same principle is at work in other aspects of datetime's
design.  For example, the proleptic Gregorian calendar is itself a
simplified approximation to reality.  In historical terms it's a
relatively recent invention, and even now it's not used in much of the
world.  So what?  It does little harm to most applications to pretend
that, e.g., 3 March 1012 is a valid Gregorian date, but simplifies
their lives, although some obsessed calendar wonk may be outraged by
such a bold fiction ;-)

It's all a "practicality beats purity" thing, but weaker than many
such things, because in this case _sometimes_ naive arithmetic is
_not_ the most practical thing.  It has been in every dateime
application I ever wrote, but I recognize that's not the universal
experience.


More information about the Python-Dev mailing list