Issue46614
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2022-02-02 17:31 by p-ganssle, last changed 2022-04-11 14:59 by admin.
Pull Requests | |||
---|---|---|---|
URL | Status | Linked | Edit |
PR 32041 | open | godlygeek, 2022-03-22 03:53 |
Messages (6) | |||
---|---|---|---|
msg412384 - (view) | Author: Paul Ganssle (p-ganssle) * | Date: 2022-02-02 17:31 | |
As part of bpo-35829, it was suggested that we add the ability to output the "Z" suffix in `isoformat()`, so that `fromisoformat()` can both be the exact functional inverse of `isoformat()` and parse datetimes with "Z" outputs. I think that that's not a particularly compelling motivation for this, but I also see plenty of examples of `datetime.utcnow().isoformat() + "Z"` out there, so it seems like this is a feature that we would want to have *anyway*, particularly if we want to deprecate and remove `utcnow`. I've spun this off into its own issue so that we can discuss how to implement the feature. The two obvious questions I see are: 1. What do we call the option? `use_utc_designator`, `allow_Z`, `utc_as_Z`? 2. What do we consider as "UTC"? Is it anything with +00:00? Just `timezone.utc`? Anything that seems like a fixed-offset zone with 0 offset? For example, do we want this? >>> LON = zoneinfo.ZoneInfo("Europe/London") >>> datetime(2022, 3, 1, tzinfo=LON).isoformat(utc_as_z=True) 2022-03-01T00:00:00Z >>> datetime(2022, 6, 1, tzinfo=LON).isoformat(utc_as_z=True) 2022-06-01T00:00:00+01:00 Another possible definition might be if the `tzinfo` is a fixed-offset zone with offset 0: >>> datetime.timezone.utc.utcoffset(None) timedelta(0) >>> zoneinfo.ZoneInfo("UTC").utcoffset(None) timedelta(0) >>> dateutil.tz.UTC.utcoffset(None) timedelta(0) >>> pytz.UTC.utcoffset(None) timedelta(0) The only "odd man out" is `dateutil.tz.tzfile` objects representing fixed offsets, since all `dateutil.tz.tzfile` objects return `None` when `utcoffset` or `dst` are passed `None`. This can and will be changed in future versions. I feel like "If the offset is 00:00, use Z" is the wrong rule to use conceptually, but considering that people will be opting into this behavior, it is more likely that they will be surprised by `datetime(2022, 3, 1, tzinfo=ZoneInfo("Europe/London").isoformat(utc_as_z=True)` returning `2022-03-01T00:00:00+00:00` than alternation between `Z` and `+00:00`. Yet another option might be to add a completely separate function, `utc_isoformat(*args, **kwargs)`, which is equivalent to (in the parlance of the other proposal) `dt.astimezone(timezone.utc).isoformat(*args, **kwargs, utc_as_z=True)`. Basically, convert any datetime to UTC and append a Z to it. The biggest footgun there would be people using it on naïve datetimes and not realizing that it would interpret them as system local times. |
|||
msg412876 - (view) | Author: Éric Araujo (eric.araujo) * | Date: 2022-02-08 22:53 | |
Would it be horrible to have the timezone instance control this? |
|||
msg413102 - (view) | Author: Matt Wozniski (godlygeek) * | Date: 2022-02-11 22:16 | |
> I feel like "If the offset is 00:00, use Z" is the wrong rule to use conceptually This is a really good point that I hadn't considered: `+00:00` and `Z` are semantically different, and just because a datetime has a UTC offset of 0 doesn't mean it should get a `Z`; `Z` is reserved specifically for UTC. It seems like the most semantically correct thing would be to only use `Z` if `tzname()` returns exactly "UTC". That would do the right thing for your London example for every major timezone library I'm aware of: >>> datetime.datetime.now(zoneinfo.ZoneInfo("Europe/London")).tzname() 'GMT' >>> datetime.datetime.now(zoneinfo.ZoneInfo("UTC")).tzname() 'UTC' >>> datetime.datetime.now(datetime.timezone.utc).tzname() 'UTC' >>> datetime.datetime.now(dateutil.tz.gettz("Europe/London")).tzname() 'GMT' >>> datetime.datetime.now(dateutil.tz.UTC).tzname() 'UTC' >>> datetime.datetime.now(pytz.timezone("Europe/London")).tzname() 'GMT' >>> datetime.datetime.now(pytz.UTC).tzname() 'UTC' I think the right rule to use conceptually is "if `use_utc_designator` is true and the timezone name is 'UTC' then use Z". We could also check the offset, but I'm not convinced we need to. |
|||
msg416622 - (view) | Author: Paul Ganssle (p-ganssle) * | Date: 2022-04-03 14:59 | |
I think this approach is probably the best we can do, but I could also imagine that users might find it to be confusing behavior. I wonder if there's any informal user testing we can do? I guess the ISO 8601 spec does call "Z" the "UTC designator", so `use_utc_designator` seems like approximately the right name. My main hesitation with this name is that I suspect users may think that `use_utc_designator` means that they *unconditionally* want to use `Z` — without reading the documentation (which we can assume 99% of users won't do) — you might assume that `dt.isoformat(use_utc_designator=True)` would translate to `dt.astimezone(timezone.utc).replace(tzinfo=None).isoformat() + "Z"`. A name like `utc_as_z` is definitely less... elegant, but conveys the concept a bit more clearly. Would be worth throwing it to a poll or something before merging. |
|||
msg416638 - (view) | Author: Éric Araujo (eric.araujo) * | Date: 2022-04-03 18:30 | |
Bad idea: pass `zulu=True` It is short, memorable if you know about it, otherwise obscure enough to push people to read the docs and be clear about what it does. Also strange and far from obvious, so a bad idea. Unless… ? |
|||
msg416648 - (view) | Author: Matt Wozniski (godlygeek) * | Date: 2022-04-04 01:30 | |
> My main hesitation with this name is that I suspect users may think that `use_utc_designator` means that they *unconditionally* want to use `Z` — without reading the documentation (which we can assume 99% of users won't do) I was thinking along similar lines when I used `use_utc_designator` in the PR, but I drew a different conclusion. I was thinking that the name `use_utc_designator` is sufficiently abstruse that no one would even be able to guess that it's referring to "Z" without actually reading the documentation for the parameter. In particular, I worry that `zulu=True` or `allow_Z=True` might lead people to make the mistake of thinking that they'll always get "Z" instead of "+00:00". > A name like `utc_as_z` is definitely less... elegant, but conveys the concept a bit more clearly. This would definitely be more memorable and more approachable. If we stick with making it conditional on `tzname() == "UTC"`, I definitely think we want to have "utc" in the name of the parameter, and `utc_as_z` satisfies that. `utc_as_z` seems reasonable to me. Let me know if you'd like me to update the PR. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:59:55 | admin | set | github: 90772 |
2022-04-04 01:30:42 | godlygeek | set | messages: + msg416648 |
2022-04-03 18:30:05 | eric.araujo | set | messages: + msg416638 |
2022-04-03 14:59:11 | p-ganssle | set | messages: + msg416622 |
2022-03-22 03:53:35 | godlygeek | set | keywords:
+ patch stage: needs patch -> patch review pull_requests: + pull_request30131 |
2022-02-11 22:16:24 | godlygeek | set | nosy:
+ godlygeek messages: + msg413102 |
2022-02-08 22:53:39 | eric.araujo | set | nosy:
+ eric.araujo messages: + msg412876 |
2022-02-02 17:31:46 | p-ganssle | create |