[Datetime-SIG] Calendar vs timespan calculations...

Alexander Belopolsky alexander.belopolsky at gmail.com
Sat Aug 1 16:36:54 CEST 2015

On Sat, Aug 1, 2015 at 1:16 AM, Tim Peters <tim.peters at gmail.com> wrote:
>> With my proposal, a naive datetime t is ambiguous in timezone tz if
>> tz.utcoffset(t) < tz.utcoffset(t.replace(first=False))
>> or "is this an invalid (missing) time?"
> Unless I'm missing your intent entirely, that's a fine illustration of
> my "The logic is bound to be annoying enough that we'd want to
> concentrate it in tzstrict".  The problem I see is that the expression
> you gave can never be true.

You are absolutely right and this is the intent.  The challenge that
I tried to solve was that local-to-global function (G(t)) can have 0, 1 or 2
values if defined as mathematical inverse of the global-to-local (L(u))
function.  (Purists would say that this means that  local-to-global
is not a function, but I find it convenient to say that a function has
multiple values when it returns a variable-length list.)  At the same
time, I wanted naive code

u = G(t)

to (a) work for all values of t; (b) produce correct result when L(u) = t
has only one solution; (c) produce one of the "correct: results when
L(u) = t has two solutions; and (d) produce "useful" result when L(u) = t
has no solutions.

This ruled out the obvious design where G(t) would return [], [u] or [u0, u1]
because all naive code that used u = G(t) would have to be rewritten as

u = G(t)[0]

and you would still face an index error when t is in the gap.  (I've recently
learned this useful terminology: the interval of non-existent local times that
occurs when you move the clock forward is called a "gap" and the the interval
of ambiguous local times that occurs when you move the clock back is called
a "fold".)

The other solution was to give G(t) an additional argument so that you could
specify the index into the returned list upfront:

def xG(t, which=0).
      return G(t)[which]

this makes the naive u = xG(t) code work in 99.99% of the cases, but you still
face an occasional index error.

So how do you represent  three outcomes [], [u] or [u0, u1] in a way that xG(t)
always works?  My solution:

[] -> [u1, u0]
[u] -> [u, u]
[u0, u1] -> [u0, u1]

Note that this solution satisfies all my design criteria including
(d).  The results
produced from the time in a gap are "useful" because the default xG(t) result
is what most people mean when they specify the time in the gap: they do it
because they are unaware of the time change and expect 02:30 AM to be 150
minutes after midnight not knowing that it will be called 03:30 AM.  The other
solution is also useful because it allows you to detect the time in the gap
without calling L(u) on the result.

More information about the Datetime-SIG mailing list