# [Datetime-SIG] Timeline arithmetic?

Tim Peters tim.peters at gmail.com
Tue Sep 8 03:54:54 CEST 2015

```[Tim]
>>>> An aware datetime _is_ a <naive datetime,
>>>> tzinfo> pair, and there's a natural bijection between naive datetimes
>>>> and POSIX timestamps (across all instants both can represent).

[Carl]
>>> I don't understand this, and I suspect it's at the heart of our
>>> misunderstanding. I would say there are many possible bijections ....

[Tim]
>> "Natural" bijection.  I gave you very simple Python code implementing
>> that bijection already.  A naive datetime represents an instant in the
>> proleptic Gregorian calendar.

[Carl]
> What is your definition of "instant" here?

I didn't need one - Occam's Razor again ;-)  To establish a bijection,
all that's required is to show that a proposed function meets all the
formal requirements.  I couldn't care less whether it does or doesn't
fit in with anyone's mental model, including my own.  "Represents an
instance" was just vague English motivation for what followed.  The
bijection was wholly defined by the latter, and never mentioned
"instant".  If it meets what someone _wants_ to think "an instant"
means. fine; if not, also fine.  Whether a proposed function is in
fact a bijection has nothing to do with anyone's opinion of what "an
instant" means, should mean, or must not mean.

But if you can't leave that alone, here:  by "an instant in the
proleptic Gregorian calendar", I mean any 5-tuple of integers that
meets the defined (by POSIX) requirements for a valid struct tm's
tm_sec, tm_min, tm_hour, tm_yday. and tm_year members.

> I don't think a naive datetime represents an instant at all;

Fine by me - and by Python.  Also fine if you _never_ use a naive datetime.

> it represents a range of possible instants,

Heh - I see you haven't defined what _you_ mean by "instant".  When
you do, please be sure it's consistent with what POSIX says here too:

The relationship between the actual time of day and the current
value for seconds since the Epoch is unspecified.

How any changes to the value of seconds since the Epoch are
made to align to a desired relationship with the current actual time
is implementation-defined. As represented in seconds since the
Epoch, each and every day shall be accounted for by exactly
86400 seconds.

While you're at it, define a clean model in which all that makes a
lick of sense to a casual user ;-)

> depending which timezone that naive datetime is interpreted
> in. Without an offset, who knows which instant it might represent.

I understand much of it is at odds with Model A.  I also understand
that some datetime libraries for other languages supply different
types for different purposes.  That's fine by me too   But we're on a
Python datetime mailing list, so in the absence of explicit statements
to the contrary, it makes most sense here to assume Python's datetime
is being discussed on its own terms.

>> So does a POSIX timestamp.  In POSIX,
>> the relationship between a timestamp and calendar notation is defined
>> by the C expression ("/" is truncating integer division):
>>
>> timestamp = tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
>>     (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
>>     ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
>>
>> The natural bijection, between naive datetimes and POSIX timestamps,
>> is the bijection in which a naive datetime maps to/from the POSIX
>> timestamp such that
>>
>>      the naive datetime's calendar notation
>>      is exactly equal to
>>      the POSIX calendar notation
>>          corresponding to that POSIX timestamp
>>          as defined by the expression above.
>>
>> Any other bijection is strained in comparison, hence "unnatural".
>> Natural doesn't necessarily mean unique (although it does in this
>> specific case - there is only one bijection satisfying the above);
>> "natural" is more related to Occam's Razor ;-)

> Ok, sure, because POSIX is defined in terms of the Gregorian calendar in
> UTC, if you have(for some reason) _must_ compare a naive datetime to a
> POSIX timestamp, it's simplest to assume the naive datetime is also in
> UTC, so that their Gregorian calendars line up with no offset.

It does happen to be an order-preserving bijection.  But I said
nothing in the quote about comparing anything apart from comparing
pairs of integers (not timestamps, and not datetimes - just the little
integers in the two calendar notations) for equality.

> I buy that's "most natural" of the available bijections in some sense, but I'm
> missing the "so what?"

The "so what?", in context, was to tweak Guido about saying an aware
datetime is fundamentally different from a <timestamp, tzinfo> pair,
despite that the space of such pairs is isomorphic to the space of
aware datetimes (which _is_ the space of <naive datetime, tzinfo>
pairs) under the natural naive_datetime <-> timestamp bijection.

Why is that setting _you_ off?  Guido handled it just fine ;-)

> Under what circumstances is it reasonable to make that assumption

Any use case where it's convenient   That's up to the user. not me -
or you.  For example, before Python grew its builtin
datetime.timezone.utc implementation of a UTC class, I routinely used
naive datetimes I thought of as being in UTC.  I was too lazy to
remember where I hid my own UTC class.  No problem.

> Rather than saying "a naive datetime simply doesn't correspond to
> any particular POSIX timestamp;  they aren't comparable at all unless
> you have additional information," which is what I'd say.

I'm starting to suspect you didn't design datetime ;-)  In context, I
datetime, naive datetimes are comparable.   Naive time has no
_concept_ of time zone.  Naive datetimes nevertheless have a  notion
of total order, which is isomorphic to the POSIX timestamp notion of
total order under the natural bijection.  Likewise for arithmetic,
etc.  There's nothing "wrong" about exploiting any of that when it's
convenient.

> I mean, I certainly hope you wouldn't want datetime to make `utcdt -
> naivedt` a defined operation where it's assumed the naive datetime is UTC.

Certainly not.  That _would_ be wrong ;-)
```