[Datetime-SIG] Adding PEP 495 support to dateutil

Akira Li 4kir4.1i at gmail.com
Sat Sep 19 05:19:33 CEST 2015


Tim Peters <tim.peters at gmail.com> writes:

> [Akira Li <4kir4.1i at gmail.com>]
>> pytz's fromutc() returns the correct* result. dateutil can't do it (at
>> the moment) https://github.com/dateutil/dateutil/issues/112
>
> Do you understand why PEP 495 is being proposed?
>

Yes, that is why I said "at the moment"

  https://www.python.org/dev/peps/pep-0495/#rationale
  https://github.com/python/peps/blob/70c78c6c48f9f025f0485f4a756b313d414b5786/pep-0495.txt#L31-L54

>> ...
>> Consider the following (natural) equality:
>>
>>   tz.fromutc(utc_time) == utc_time.replace(tzinfo=utc_tz).astimezone(tz)
>
> Clear as mud to me ;-)
>
>
>> The right side allows *utc_time.tzinfo* being None or *utc_time.tzinfo*
>> may be some equivalent of *timezone.utc*.
>
> Since the RHS replaces utc_time.tzinfo before using utc_time, the RHS
> "allows" utc_time.tzinfo to be anything whatsoever at the start.

"anything whatsover" would conflict with the _name_ *utc_time*.

If *utc_time* is a naive datetime object then it may be interpreted as utc
time in a given program.

If *utc_time* is timezone-aware then utc_time.tzinfo being an equivalent
of timezone.utc is not surprising too.

>> It is confusing that the method named *fromutc()* (its stdlib implementation)
>> rejects *utc_time* if it is in utc timezone.
>
> But your use, despite your claim of being "natural", is highly
> _un_natural.  The natural use of .astimezone() is to invoke it _from_
> a datetime object:
>
>     a_datetime.astimezone(tz)
>
> .fromutc() was rarely intended to be invoked directly, except perhaps
> by tzinfo authors.  In that context, its real use is to help implement
> .astimezone(),  And its calling conventions are natural in that
> context:
>
>     def datetime.astimezone(self, tz):
>         myoffset = self.utcoffset()
>         utc = (self - myoffset).replace(tzinfo=tz)
>         return tz.fromutc(utc)
>
>
>
>> stdlib's behavior that mandates utc_time.tzinfo == tz
>
> Not "==", "is".

Yes, it was an error. Though it does not change the meaning of the
sentence i.e., any value except None or timezone.utc analog is
surprising for utc_time.tzinfo

>> where tz may have non-zero utc offset is weird (mind-bending --
>> input time must be utc but tzinfo is not utc -- wtf). There is no
>> need to attach *tz* before calling *tz.fromutc()* -- tz is passed
>> as *self* anyway.
>
> Redundancy helps catch programming errors.  I know darned well this
> check helped catch errors I made when implementing this stuff to begin
> with.  There's always potential confusion when one object delegates
> operations to operations of the same names implemented by a contained
> object.
>
> If you don't like it, tough ;-)  Stick to using astimezone() and leave
> the internals alone.  If you are going to play with the internals,
> follow the rules,  It's not like they weren't documented ;-)

To be clear, it is not a suggestion to change anything in stdlib. It was
a reaction to the earlier message in this thread, to point out why
stdlib's fromutc() API is not the example that should be followed. Thank
you for providing the explicit reasons for the specific choices in the
API design: "redundency helps" and fromutc() is semi-private. I can't
remember when I've used fromutc() directly (It is used indirectly via
datetime.now(tz), datetime.fromtimestamp(ts, tz), d.astimezone(tz),
tz.normalize()).


More information about the Datetime-SIG mailing list