[Zope3-dev] Can we remove ZopeLegacy for now?

Tim Peters tim@zope.com
Sat, 16 Mar 2002 15:59:11 -0500


[Tim, copies Indiana rules]

[Guido]
> I don't see the mess, unless you make the mistake of thinking of
> Indiana as one timezone.  Of course it isn't!  There are three
> different timezones (using the definition of timezone as "a group of
> clocks that show the same time, by agreement"): US/Eastern,
> US/Central, and EST.

As before, I prefer to think of it as two timezones with 3 sets of DST
rules, but I'll play along.  Note that I was specifically responding to
your:

   even the combination of tm_zone and tm_isdst isn't enough to
   unambiguously determine the DST transition points (unless you
                                                      ^^^^^^^^^^
   are in the US).
   ^^^^^^^^^^^^^

I didn't (and don't) see any simplification here for people who are in the
US.

> ...
> Let me clarify what I meant by "you don't have enough information".
> The struct tmx stores a "time zone" which is really an offset from
> UTC, and a "DST offset".
>
> Now suppose I present you with a time, say March 16, 2002, 12:21:00,
> and I tell you the UTC offset (-5 hours) and the DST offset (zero,
> meaning DST is not in effect on this date).  Now let's try to do some
> date/time arithmetic.  What UTC offset and DST are in effect exactly
> two months later?  Or exactly two months earlier?

I can't tell, and note that the answer is the same even if I'm told this all
takes place in the US (picture two people in Indiana living in the same time
zone (by my meaning) but under different DST rules:  they can have the same
UTC + DST offsets at one point in time, but not two months later).  I wasn't
confused by your claim that there's not enough information, I was confused
by your claim that the US was somehow exempt from ambiguity.

OTOH, if you can write a tzinfo object that captures the rules for someone
in Texas or for a specific person in Indiana, I'm sure you could also write
a customized set of functions for them based on a tmx too.  The C standard
doesn't supply sufficient routines on its own; but neither does a datetime
object on its own.

Also note that if the offsets aren't all mushed together, I *can* tell that
the timezone (in my sense of the word) hasn't changed (it never changes,
barring political shenanigans).  The only thing that's uncertain is the DST
component of the aggregate offset two months later.

> - It could be US/Eastern, and two month later the UTC offset will be
>   -4 hours and the DST will be 1 hour; two months earlier will be
>   unchanged.
>
> - It could be some place near the equator, and the UTC offset would
>   remain -5 hours and the DST would remain unset throughout the year.
>
> - It could be Chile; two months later would be -5 hours, two months
>   earlier would be their DST, and so the offset would be -4 hours then.
>
> Now, the tmx structure allows an extension, so an implementation could
> hide additional information there, but I doubt that's what you were
> referring to, and in any case a portable app can't rely on it.

All agreed.

> In my design, however, the tzinfo object can implement any set of
> rules you want;

I don't know about that yet -- see earlier msg reraising your "chemical
plant" example.

> it has a defined interface (methods tzoffset(), tzname(), and tzdst(),
> each taking a datetime instance).  How does that work?  There are
> distinct tzinfo instances (or classes) that implement the rules for
> Chile, US/Eastern, Equador, and so on.

Yet we can find two people living in US/Eastern who follow different DST
rules.  It's easiest to find them by looking in Indiana <wink>.
"US/Eastern" is simply ill-defined if it's meant to encompass *all*
localtime information needed by people who swear they live in US/Eastern.

> There's no single tzinfo object for US/Indiana; times in Indiana must
> somehow choose the tzinfo object that applies to the county where the
> time is taken.

Agreed.

>> The base code

> Exactly what base code?  You mean what we had before we dropped
> tzoffset from the prototype implementation?

I mean whatever code ends up being the datetime class (as distiguished from
the datetimetz class) -- the "base class", if you will.


>>               can't get in trouble because of this simply because
>> our spec declines to say anything about what this number means,
>> beyond that it's "seconds east of UTC".  I'm not sure that's
>> enforcable-- or even meaningful --in the absence of other defined
>> semantics.  It reads more like a hint about intent.

> I don't understand what you're trying to say here.  But that may be no
> more than fair: you probably don't understand what I had in mind for
> the tzinfo object, because I haven't finished writing it up (still
> haven't).

I expect that's true.  At the time I wrote this, the Wiki said very little
concrete about tzinfo objects.

> Yeah, you learn a lot of nonsense in grade school.  As became clear in
> other messages in this thread, the word "timezone" means many things
> to many people.

That's why I find it clarifying to break it into distinct components.  Then
it becomes possible to speak with precision, or at least as much precision
as politicians and religious authorities can bear ...

For most of the rest, I'll do us both a favor and wait for the Wiki to catch
up with your thoughts.  Heck, if I can channel them, I'll even help <wink>.

> ...
> And I suppose if there's a use case for asking a datetimetz object
> whether DST is in effect, that question, too, is passed on to the
> tzinfo object.

My own use case for that is discoverability:  if a tzinfo object claims to
incorporate knowledge of DST rules, I'd like a direct way to query it about
what it believes at any given time (preferably not just "yes" or "no", but a
signed duration, as in a tmx and as in ECMAScript).  Since DST is such a
mess, discoverability is a debugging tool for when things go wrong.

>>> Sample tzinfo classes:
>>>
>>>        class UTC:
>>>            "UTC"
>>>           def tzoffset(self, dt):
>>>                return 0
>>>           def tzname(self, dt):
>>>                return "UTC"

>> I assume it's just as valid to define this as, e.g.,
>>
>>         class UTC:
>>             "UTC"
>>            def tzoffset(self, dt):
>>                 return -42137    # ONLY CHANGE IS HERE
>>            def tzname(self, dt):
>>                 return "UTC"
>>
>> If it's not, scream at me, because then there's some hidden
>> assumption about the relationship between naive time and UTC.  Or is
>> the rest of the spec going to change to say that naive time *is* UTC
>> (but stripped of leap secconds)?  That assumption seems to underlie
>> all the sample classes: is it a required assumption, or just a
>> convenient assumption for purposes of illustration?

> SCREAM!!!  Returning -42137 is *not* the same as returning zero!!!

Of course it isn't, and that's the point.  Up until now, you've said:

    [from <http://www.zope.org/Members/fdrake/DateTimeWiki/NaiveTime>]
    Whether a datetime object represents UTC, local time, or time in
    some other timezone is purely up to the program; just like it's up
    to the program whether a particular number represents meters, miles,
    or mass.

If you're now telling me that I'm not allowed to pretend a datetime object
is 42137 seconds removed from UTC, then the nature of "naive time" has
changed.  [Oops:  I see the defn of tzoffset() has changed to minutes now --
whatever.]

Or does "dt" in the example not refer to an arbitrary datetime object, but
only to a (subclass of) datetimetz?  Even then, I should be able to make up
any silly rules I want <wink>.

> I'm not sure where the misunderstanding is.  Naive datetime doesn't
> have an explicit timezone, but it could have an implied timezone that
> the application knows.

Presumably my application wants to believe a naive datetime is 42137
sec^H^H^H minutes off from UTC.  In that case I believe my app's version of
a UTC tzinfo object must return +-42137 when a naive datetime is passed to
its tzoffset() method.

> The datetimetz class is intended to make the timezone explicit.

Sure.  And if I, e.g., live in a DST-free part of the world, and choose to
believe that a naive datetime *is* my local time, then my version of a UTC
tzinfo object is going to have to take my belief into account.

An alternative (and probably saner <wink>) is to stop saying that "naive
time" makes no assumptions, but that when combined with a tzinfo object it
specifically assumes UTC stripped of leap seconds, and users have no choice
about that.  Then your example classes are compelling.

> When I create a datetimetz object, I pass in a tzinfo object that
> represents the timezone semantics I want to use for this datetimetz
> object.  So if I am going to record times in UTC, I pass an instance
> (or maybe *the* instance :-) of the UTC class.

If your app chooses to believe that "naive" datetimes are at an offset of 0
from UTC, or the spec changes to *require* that belief when using tzinfo
objects, fine by me.  The sample UTC class doesn't make sense unless that's
what you do choose (or are forced) to believe.

...
>> BTW, I'm delighted to punt the nasty issues into the court of a
>> vague object.

> I object to calling the tzoffset object vague.  It's got a precise
> interface.

Vague wasn't meant as pejorative.  Indeed, the strength of a tzinfo relies
on what it *doesn't* specify.  I meant "vague" only in the sense of
"unspecified".  Freedom of speech is also vague, and I'm not opposed to it
either <wink>.